sintonia/library/ecasound-2.7.2/libecasound/eca-control-objects.cpp

2532 lines
66 KiB
C++
Raw Blame History

// ------------------------------------------------------------------------
// eca-control-objects.cpp: Class for configuring libecasound objects
// Copyright (C) 2000-2004,2006,2008,2009 Kai Vehmanen
// Copyright (C) 2005 Stuart Allie
//
// Attributes:
// eca-style-version: 3 (see Ecasound Programmer's Guide)
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// ------------------------------------------------------------------------
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <kvu_dbc.h> /* DBC_* */
#include <kvu_value_queue.h>
#include <kvu_temporary_file_directory.h>
#include <kvu_numtostr.h>
#include <kvu_utils.h> /* kvu_get_argument_number() */
#include "audioio.h"
#include "eca-chain.h"
#include "eca-chainop.h"
#include "eca-chainsetup.h"
#include "eca-control.h"
#include "eca-engine.h"
#include "eca-object-factory.h"
#include "eca-session.h"
#include "generic-controller.h"
#include "eca-error.h"
#include "eca-logger.h"
/**
* Import namespaces
*/
using std::string;
/**
* Definitions for member functions
*/
/**
* Adds a new chainsetup
*
* @param name chainsetup name
*
* require:
* name != ""
*
* ensure:
* selected_chainsetup() == name || (last_error().size() > 0 && no_errors != true)
*/
void ECA_CONTROL::add_chainsetup(const string& name)
{
// --------
DBC_REQUIRE(name != "");
// --------
bool no_errors = true;
int count = static_cast<int>(session_repp->chainsetups_rep.size());
session_repp->add_chainsetup(name);
if (static_cast<int>(session_repp->chainsetups_rep.size()) > count) {
select_chainsetup(name);
ECA_LOG_MSG(ECA_LOGGER::info, "Added a new chainsetup with name \"" + name + "\".");
}
else {
set_last_error("Unable to add chainsetup with name \"" + name + "\".");
no_errors = false;
}
// --------
DBC_ENSURE(selected_chainsetup() == name || (last_error().size() > 0 && no_errors != true));
// --------
}
/**
* Removes chainsetup
*
* @param name chainsetup name
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
*
* ensure:
* selected_chainsetup.empty() == true
*/
void ECA_CONTROL::remove_chainsetup(void)
{
// --------
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(is_selected() == true);
// --------
ECA_LOG_MSG(ECA_LOGGER::info, "Removing chainsetup: \"" + selected_chainsetup() + "\".");
session_repp->remove_chainsetup();
selected_chainsetup_repp = 0;
// --------
DBC_ENSURE(selected_chainsetup().empty() == true);
// --------
}
/**
* Loads chainsetup from file 'filename'.
*
* @param name chainsetup filename
*
* require:
* filename != ""
*
* ensure:
* filename exists implies loaded chainsetup == selected_chainsetup()
*/
void ECA_CONTROL::load_chainsetup(const string& filename)
{
try {
session_repp->load_chainsetup(filename);
selected_chainsetup_repp = session_repp->selected_chainsetup_repp;
DBC_CHECK((selected_chainsetup_repp != 0 &&
selected_chainsetup_repp->filename() == filename) ||
selected_chainsetup_repp == 0);
ECA_LOG_MSG(ECA_LOGGER::info, "Loaded chainsetup from file \"" + filename + "\".");
}
catch(ECA_ERROR& e) {
set_last_error(e.error_section() + ": \"" + e.error_message() + "\"");
}
}
/**
* Save selected chainsetup.
*
* @param filename chainsetup filename (if omitted, previously used filename will be used, if any)
*
* require:
* selected_chainsetup().empty() != true
*/
void ECA_CONTROL::save_chainsetup(const string& filename)
{
// --------
DBC_REQUIRE(selected_chainsetup().empty() != true);
// --------
try {
if (filename.empty() == true)
session_repp->save_chainsetup();
else
session_repp->save_chainsetup(filename);
ECA_LOG_MSG(ECA_LOGGER::info, "Saved selected chainsetup \"" + selected_chainsetup() + "\".");
}
catch(ECA_ERROR& e) {
set_last_error(e.error_section() + ": \"" + e.error_message() + "\"");
}
}
/**
* Selects chainsetup
*
* @param name chainsetup name
*
* require:
* name != ""
*
* ensure:
* name == selected_chainsetup() ||
* selected_chainsetup_rep == 0
*/
void ECA_CONTROL::select_chainsetup(const string& name)
{
// --------
DBC_REQUIRE(name != "");
// --------
session_repp->select_chainsetup(name);
selected_chainsetup_repp = session_repp->selected_chainsetup_repp;
if (selected_chainsetup_repp == 0) {
ECA_LOG_MSG(ECA_LOGGER::info, "Chainsetup \"" + name + "\" doesn't exist!");
set_last_error("Chainsetup \"" + name + "\" doesn't exist!");
}
// else { ECA_LOG_MSG(ECA_LOGGER::info, "Selected chainsetup: \"" + selected_chainsetup() + "\"."); }
// --------
DBC_ENSURE(name == selected_chainsetup() ||
is_selected() == false);
// --------
}
/**
* Selects a chainsetup by index.
*
* @param index_number an integer identifier
*
* require:
* index_number > 0
*/
void ECA_CONTROL::select_chainsetup_by_index(int index_number)
{
// --------
DBC_REQUIRE(index_number > 0);
// --------
for(std::vector<ECA_CHAINSETUP*>::size_type p = 0;
p != session_repp->chainsetups_rep.size();
p++) {
if (index_number == static_cast<int>(p + 1)) {
select_chainsetup(session_repp->chainsetups_rep[p]->name());
break;
}
}
}
/**
* Name of currently active chainsetup
*/
string ECA_CONTROL::selected_chainsetup(void) const
{
if (selected_chainsetup_repp != 0)
return selected_chainsetup_repp->name();
return "";
}
/**
* Spawns an external editor for editing selected chainsetup
*
* require:
* is_selected()
* connected_chainsetup() != selected_chainsetup()
*/
void ECA_CONTROL::edit_chainsetup(void)
{
// --------
DBC_REQUIRE(selected_chainsetup().empty() != true);
// --------
/* 1. check which editor to use (and exit if none
* defined) */
string editori = "";
string use_getenv =
resource_value("ext-cmd-text-editor-use-getenv");
if (use_getenv.size() == 0 ||
use_getenv == "true") {
/* note: as specified in ecasoundrc(5), we should
* default to 'true' */
if (std::getenv("EDITOR") != 0) {
editori = std::getenv("EDITOR");
}
}
if (editori == "")
editori = resource_value("ext-cmd-text-editor");
if (editori == "") {
ECA_LOG_MSG(ECA_LOGGER::info,
"ERROR: Cannot edit, no text editor specified/available. See ecasoundrc(5) man page and the 'ext-cmd-text-editor' configuration variable.");
return;
}
/* 2. detect hot-swap */
bool hot_swap = false;
bool restart = false;
if (connected_chainsetup() == selected_chainsetup()) {
hot_swap = true;
if (is_running()) restart = true;
}
/* 3. store runtime state of the old chainsetup */
string origname = selected_chainsetup_repp->name();
string origfilename = selected_chainsetup_repp->filename();
SAMPLE_SPECS::sample_pos_t origpos = selected_chainsetup_repp->position_in_samples();
/* 4. create a safely accessible temporary filename */
TEMPORARY_FILE_DIRECTORY tempfile_dir_rep;
string tmpdir ("ecasound-");
char* tmp_p = std::getenv("USER");
if (tmp_p != NULL) {
tmpdir += string(tmp_p);
tempfile_dir_rep.reserve_directory(tmpdir);
}
if (tempfile_dir_rep.is_valid() != true) {
ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: Unable to create temporary directory \"" + tmpdir + "\".");
return;
}
string filename = tempfile_dir_rep.create_filename("cs-edit-tmp", ".ecs");
/* 5. save selected chainsetup to the temp file */
if (hot_swap == true)
session_repp->connected_chainsetup_repp->set_name("cs-edit-temp");
save_chainsetup(filename);
if (hot_swap == true)
session_repp->connected_chainsetup_repp->set_name(origname);
else
remove_chainsetup();
/* 6. fork an external text editor */
// FIXME: we should drop priviledge-level here (at least if root)!
editori += " " + filename;
int res = ::system(editori.c_str());
if (res == 127 || res == -1) {
ECA_LOG_MSG(ECA_LOGGER::info, "Can't edit; unable to open file in text editor \"" + string(editori.c_str()) + "\".");
}
else {
/* 7. reload the edited chainsetup and reset runtime state */
load_chainsetup(filename);
if (is_selected() != true) {
ECA_LOG_MSG(ECA_LOGGER::info,
std::string("Unable to parse chainsetup, keeping the temporary file ") + filename);
}
else {
remove(filename.c_str());
if (origfilename.empty() != true) {
set_chainsetup_filename(origfilename);
}
if (selected_chainsetup_repp)
selected_chainsetup_repp->seek_position_in_samples(origpos);
if (hot_swap == true) {
/* 7.1 disconnect the chainsetup to be replaced */
disconnect_chainsetup();
/* 7.2 try to connect the edited chainsetup */
select_chainsetup("cs-edit-temp");
if (is_valid() == true) {
connect_chainsetup(0);
/* should succeed as is_valid() is true */
DBC_CHECK(is_connected() == true);
if (is_connected() == true) {
if (restart == true) {
DBC_CHECK(is_running() != true);
start();
}
}
}
/* 7.3 if connecting the modified chainsetup fails */
if (is_connected() != true) {
ECA_LOG_MSG(ECA_LOGGER::info, "Can't connect; edited chainsetup is not valid.");
}
/* 7.4 remove the old chainsetup */
select_chainsetup(origname);
remove_chainsetup();
select_chainsetup("cs-edit-temp");
selected_chainsetup_repp->set_name(origname);
}
}
}
}
/**
* Sets processing length in seconds.
*
* require:
* is_selected() == true
* value >= 0
*/
void ECA_CONTROL::set_chainsetup_processing_length_in_seconds(double value)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
// --------
/* note! here we set the _maximum_ length of the chainsetup */
selected_chainsetup_repp->set_max_length_in_seconds(value);
ECA_LOG_MSG(ECA_LOGGER::info, "Set chainsetup processing length to \"" + kvu_numtostr(value) + "\" seconds.");
}
/**
* Sets processing length in samples. If 'value' is 0,
* length in unspecified.
*
* require:
* is_selected() == true
* value >= 0
*/
void ECA_CONTROL::set_chainsetup_processing_length_in_samples(SAMPLE_SPECS::sample_pos_t value)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
// --------
/* note! here we set the _maximum_ length of the chainsetup */
selected_chainsetup_repp->set_max_length_in_samples(value);
ECA_LOG_MSG(ECA_LOGGER::info, "Set chainsetup processing length to \"" +
kvu_numtostr(selected_chainsetup_repp->max_length_in_seconds_exact()) + "\" seconds.");
}
/**
* Sets default open mode for audio outputs.
*
* require:
* output_mode == AUDIO_IO::io_write || output_mode == AUDIO_IO::io_readwrite
*/
void ECA_CONTROL::set_chainsetup_output_mode(int output_mode)
{
// --------
DBC_REQUIRE(output_mode == AUDIO_IO::io_write || output_mode == AUDIO_IO::io_readwrite);
// --------
selected_chainsetup_repp->set_output_openmode(output_mode);
}
/**
* Sets chainsetup buffersize (in samples).
*
* @pre is_selected() == true
*/
void ECA_CONTROL::set_chainsetup_buffersize(int bsize)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
selected_chainsetup_repp->set_buffersize(bsize);
}
/**
* Toggles chainsetup looping
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::toggle_chainsetup_looping(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
// --------
if (selected_chainsetup_repp->looping_enabled()) {
selected_chainsetup_repp->toggle_looping(false);
ECA_LOG_MSG(ECA_LOGGER::info, "Disabled looping.");
}
else {
selected_chainsetup_repp->toggle_looping(true);
ECA_LOG_MSG(ECA_LOGGER::info, "Enabled looping.");
}
}
/**
* Connects selected chainsetup
*
* require:
* is_selected() == true
* is_valid() == true
*
* ensure:
* is_connected() == true || (last_error().size() > 0 && no_errors != true)
*/
void ECA_CONTROL::connect_chainsetup(struct eci_return_value *retval)
{
// --------
DBC_REQUIRE(is_selected());
DBC_REQUIRE(selected_chainsetup_repp != 0 && selected_chainsetup_repp->is_valid() == true);
// --------
bool no_errors = true;
string errmsg;
if (is_connected() == true) {
disconnect_chainsetup();
}
try {
session_repp->connect_chainsetup();
ECA_LOG_MSG(ECA_LOGGER::subsystems, "Connected chainsetup: \"" + connected_chainsetup() + "\"");
}
catch(ECA_ERROR& e) {
errmsg = e.error_message();
no_errors = false;
}
if (is_connected() != true) {
set_last_error(" Connecting chainsetup failed: \"" + errmsg + "\"");
no_errors = false;
}
fill_command_retval(retval);
// --------
DBC_ENSURE(is_connected() || no_errors != true);
// --------
}
/**
* Name of connected chainsetup.
*/
string ECA_CONTROL::connected_chainsetup(void) const
{
if (session_repp->connected_chainsetup_repp != 0) {
return session_repp->connected_chainsetup_repp->name();
}
return "";
}
/**
* Disconnects activate chainsetup
*
* require:
* is_connected() == true
*
* ensure:
* connected_chainsetup() == ""
*/
void ECA_CONTROL::disconnect_chainsetup(void)
{
// --------
DBC_REQUIRE(is_connected());
// --------
if (is_engine_running() == true) {
stop_on_condition();
}
if (is_engine_created()) {
close_engine();
}
ECA_LOG_MSG(ECA_LOGGER::info, "Disconnecting chainsetup: \"" + connected_chainsetup() + "\".");
session_repp->disconnect_chainsetup();
// --------
DBC_ENSURE(connected_chainsetup() == "");
// --------
}
/**
* Changes the chainsetup position relatively to the current position.
* Behaves differently depending on whether the selected
* chainsetup is connected or not.
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::change_chainsetup_position(double seconds)
{
// --------
DBC_REQUIRE(is_selected());
// --------
// FIXME: check whether all audio devices support seeking,
// raise an error if not (note: see other similar FIXMEs)
if (connected_chainsetup() == selected_chainsetup() && is_engine_running() == true) {
if (seconds < 0)
engine_repp->command(ECA_ENGINE::ep_rewind, -seconds);
else
engine_repp->command(ECA_ENGINE::ep_forward, seconds);
}
else {
selected_chainsetup_repp->seek_position_in_seconds(selected_chainsetup_repp->position_in_seconds()
+ seconds );
}
}
/**
* Changes the chainsetup position in samples relatively to the
* current position. Behaves differently depending on whether
* the selected chainsetup is connected or not.
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::change_chainsetup_position_samples(SAMPLE_SPECS::sample_pos_t samples)
{
// --------
DBC_REQUIRE(is_selected());
// --------
// FIXME: check whether all audio devices support seeking,
// raise an error if not (note: see other similar FIXMEs)
if (connected_chainsetup() == selected_chainsetup() && is_engine_running() == true) {
change_chainsetup_position(static_cast<double>(samples) /
selected_chainsetup_repp->samples_per_second());
}
else {
selected_chainsetup_repp->seek_position_in_samples(selected_chainsetup_repp->position_in_samples()
+ samples );
}
}
/**
* Sets the chainsetup position. Behaves differently depending on
* whether the selected chainsetup is connected or not.
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::set_chainsetup_position(double seconds)
{
// --------
DBC_REQUIRE(is_selected());
// --------
// FIXME: check whether all audio devices support seeking,
// raise an error if not (note: see other similar FIXMEs)
if (connected_chainsetup() == selected_chainsetup() && is_engine_running() == true) {
engine_repp->command(ECA_ENGINE::ep_setpos, seconds);
}
else {
selected_chainsetup_repp->seek_position_in_seconds(seconds);
}
}
/**
* Sets the chainsetup position in samples.. Behaves
* differently depending on whether the selected chainsetup
* is connected or not.
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::set_chainsetup_position_samples(SAMPLE_SPECS::sample_pos_t samples)
{
// --------
DBC_REQUIRE(is_selected());
// --------
// FIXME: check whether all audio devices support seeking,
// raise an error if not (note: see other similar FIXMEs)
if (connected_chainsetup() == selected_chainsetup() && is_engine_running() == true) {
set_chainsetup_position(static_cast<double>(samples) /
selected_chainsetup_repp->samples_per_second());
}
else {
selected_chainsetup_repp->seek_position_in_samples(samples);
}
}
/**
* Gets a vector of al chainsetup names.
*/
std::vector<string> ECA_CONTROL::chainsetup_names(void) const
{
return session_repp->chainsetup_names();
}
/**
* Gets a pointer to selected chainsetup, or 0 if no
* chainsetup is selected.
*/
const ECA_CHAINSETUP* ECA_CONTROL::get_chainsetup(void) const
{
return selected_chainsetup_repp;
}
/**
* Gets a pointer to connected chainsetup, or 0 if no
* chainsetup is selected.
*/
const ECA_CHAINSETUP* ECA_CONTROL::get_connected_chainsetup(void) const
{
return session_repp->connected_chainsetup_repp;
}
/**
* Gets a pointer to chainsetup with filename 'filename'.
*/
const ECA_CHAINSETUP* ECA_CONTROL::get_chainsetup_filename(const string&
filename) const
{
std::vector<ECA_CHAINSETUP*>::const_iterator p = session_repp->chainsetups_rep.begin();
while(p != session_repp->chainsetups_rep.end()) {
if ((*p)->filename() == filename) {
return (*p);
}
++p;
}
return 0;
}
/**
* Returns current buffersize of selected chainsetup.
*
* <20>pre is_selected() == true
*/
int ECA_CONTROL::chainsetup_buffersize(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
return selected_chainsetup_repp->buffersize();
}
/**
* Gets chainsetup filename (used by save_chainsetup())
*
* <20>pre is_selected() == true
*/
const string& ECA_CONTROL::chainsetup_filename(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
return selected_chainsetup_repp->filename();
}
/**
* Sets chainsetup filename (used by save_chainsetup())
*
* require:
* is_selected() == true &&
* name.empty() != true
*/
void ECA_CONTROL::set_chainsetup_filename(const string& name)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(name.empty() != true);
// --------
selected_chainsetup_repp->set_filename(name);
}
/**
* Sets general chainsetup chainsetup parameter
*
* require:
* is_selected() == true &&
* name.empty() != true
*/
void ECA_CONTROL::set_chainsetup_parameter(const string& name)
{
// --------
DBC_REQUIRE(is_selected() == true &&
name.empty() != true);
// --------
selected_chainsetup_repp->interpret_global_option(name);
if (selected_chainsetup_repp->interpret_result() != true) {
/* for instance -f:xxx options are handle by
* object-specific parsing */
selected_chainsetup_repp->interpret_object_option(name);
}
}
/**
* Sets general chainsetup chainsetup parameter
*
* require:
* is_selected() == true &&
* name.empty() != true
*/
void ECA_CONTROL::set_chainsetup_sample_format(const string& name)
{
// --------
DBC_REQUIRE(is_selected() == true &&
name.empty() != true);
// --------
selected_chainsetup_repp->interpret_object_option("-f:" + name);
if (selected_chainsetup_repp->interpret_result() != true) {
set_last_error(selected_chainsetup_repp->interpret_result_verbose());
}
}
/**
* Adds a new chain (selected chainsetup). Added chain is automatically
* selected.
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
*
* ensure:
* selected_chains().size() > 0
*/
void ECA_CONTROL::add_chain(const string& name)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chainsetup() != connected_chainsetup());
// --------
add_chains(std::vector<string> (1, name));
// --------
DBC_ENSURE(selected_chains().size() > 0);
// --------
}
/**
* Adds new chains (selected chainsetup). Added chains are automatically
* selected.
*
* @param names comma separated list of chain names
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
*
* ensure:
* selected_chains().size() > 0
*/
void ECA_CONTROL::add_chains(const string& names)
{
// --------
DBC_REQUIRE(is_selected() == true &&
(session_repp->connected_chainsetup_repp !=
session_repp->selected_chainsetup_repp));
// --------
add_chains(kvu_string_to_vector(names, ','));
// --------
DBC_ENSURE(selected_chains().size() > 0);
// --------
}
/**
* Adds new chains (selected chainsetup). Added chains are automatically
* selected.
*
* @param namess vector of chain names
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
*
* ensure:
* selected_chains().size() == names.size()
*/
void ECA_CONTROL::add_chains(const std::vector<string>& new_chains)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
// --------
selected_chainsetup_repp->add_new_chains(new_chains);
selected_chainsetup_repp->select_chains(new_chains);
ECA_LOG_MSG(ECA_LOGGER::info, "Added chains: " + kvu_vector_to_string(new_chains, ", ") + ".");
// --------
DBC_ENSURE(selected_chains().size() == new_chains.size());
// --------
}
/**
* Removes currently selected chain (selected chainsetup)
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
* selected_chains().size() > 0 &&
*
* ensure:
* selected_chains().size() == 0
*/
void ECA_CONTROL::remove_chains(void)
{
// --------
DBC_REQUIRE(is_selected() == true &&
selected_chains().size() > 0 &&
(session_repp->connected_chainsetup_repp !=
session_repp->selected_chainsetup_repp));
// --------
selected_chainsetup_repp->remove_chains();
ECA_LOG_MSG(ECA_LOGGER::info, "(eca-controlled) Removed selected chains.");
// --------
DBC_ENSURE(selected_chains().size() == 0);
// --------
}
/**
* Selects a set of chains using index numbers. Previously
* selected chains are first all deselected.
*
*
* @param index_numbers set of integer identifiers
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::select_chains_by_index(const std::vector<int>& index_numbers)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
std::vector<string> selchains;
for(std::vector<CHAIN*>::size_type p = 0;
p != selected_chainsetup_repp->chains.size();
p++) {
for(std::vector<int>::size_type q = 0;
q != index_numbers.size();
q++) {
if (index_numbers[q] == static_cast<int>(p + 1)) {
selchains.push_back(selected_chainsetup_repp->chains[p]->name());
break;
}
}
}
select_chains(selchains);
}
/**
* Selects a chains (currently selected chainsetup). Previously
* selected chains are first all deselected.
*
* require:
* is_selected() == true
*
* ensure:
* selected_chains().size() == 1
*/
void ECA_CONTROL::select_chain(const string& chain)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
std::vector<string> c (1);
c[0] = chain;
selected_chainsetup_repp->select_chains(c);
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "Selected chain: " + chain + ".");
// --------
DBC_ENSURE(selected_chains().size() == 1);
// --------
}
/**
* Selects chains (currently selected chainsetup). Previously
* selected chains are first all deselected.
*
* @param chains vector of chain names
*
* require:
* is_selected() == true
*
* ensure:
* selected_chains().size() > 0
*/
void ECA_CONTROL::select_chains(const std::vector<string>& chains)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
selected_chainsetup_repp->select_chains(chains);
// ECA_LOG_MSG(ECA_LOGGER::user_objects, "Selected chains: " +
// vector_to_string(chains, ", ") + ".");
}
/**
* Deselects chains (currently selected chainsetup)
*
* @param chains vector of chain names
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::deselect_chains(const std::vector<string>& chains)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
std::vector<string> schains = selected_chainsetup_repp->selected_chains();
std::vector<string>::const_iterator p = chains.begin();
while(p != chains.end()) {
std::vector<string>::iterator o = schains.begin();
while(o != schains.end()) {
if (*p == *o) {
// ECA_LOG_MSG(ECA_LOGGER::info, "(eca-controller-objects) Deselected chain " + *o + ".");
schains.erase(o);
}
else
++o;
}
++p;
}
selected_chainsetup_repp->select_chains(schains);
}
/**
* Selects all chains (currently selected chainsetup)
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::select_all_chains(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
selected_chainsetup_repp->select_all_chains();
// ECA_LOG_MSG(ECA_LOGGER::info, "Selected chains: " + vector_to_string(selected_chains(), ", ") + ".");
}
/**
* Returns a list of selected chains (currently selected chainsetup)
*
* require:
* is_selected() == true
*/
const std::vector<string>& ECA_CONTROL::selected_chains(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
return selected_chainsetup_repp->selected_chains();
}
/**
* Gets a vector of all chain names.
*
* require:
* is_selected() == true
*/
std::vector<string> ECA_CONTROL::chain_names(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
return selected_chainsetup_repp->chain_names();
}
/**
* Gets a pointer to selected chain, or 0 if no chain is selected.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
const CHAIN* ECA_CONTROL::get_chain(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
const std::vector<string>& schains = selected_chainsetup_repp->selected_chains();
std::vector<string>::const_iterator o = schains.begin();
while(o != schains.end()) {
for(std::vector<CHAIN*>::size_type p = 0;
p != selected_chainsetup_repp->chains.size();
p++) {
if (selected_chainsetup_repp->chains[p]->name() == *o)
return selected_chainsetup_repp->chains[p];
}
++o;
}
return 0;
}
/**
* Clears all selected chains (all chain operators and controllers
* are removed)
*
* @param name chain name
*
* require:
* is_selected() == true
* is_running() != true
*/
void ECA_CONTROL::clear_chains(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(is_running() != true);
// --------
selected_chainsetup_repp->clear_chains();
}
/**
* Clears all selected chains (all chain operators and controllers
* are removed)
*
* @param name chain name
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
* selected_chains().size() == 1
*/
void ECA_CONTROL::rename_chain(const string& name)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(selected_chains().size() == 1);
// --------
selected_chainsetup_repp->rename_chain(name);
}
void ECA_CONTROL::send_chain_commands_to_engine(int command, double value)
{
// --------
DBC_CHECK(is_engine_running() == true);
// --------
if (is_engine_running() != true) return;
const std::vector<string>& schains = selected_chainsetup_repp->selected_chains();
std::vector<string>::const_iterator o = schains.begin();
while(o != schains.end()) {
for(std::vector<CHAIN*>::size_type p = 0;
p != selected_chainsetup_repp->chains.size();
p++) {
if (selected_chainsetup_repp->chains[p]->name() == *o) {
engine_repp->command(ECA_ENGINE::ep_c_select, p);
engine_repp->command(static_cast<ECA_ENGINE::Engine_command_t>(command), value);
break;
}
}
++o;
}
}
/**
* Toggles whether chain is muted or not
*
* require:
* is_selected() == true
* selected_chains().size() > 0
*/
void ECA_CONTROL::toggle_chain_muting(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() > 0);
// --------
if (connected_chainsetup() == selected_chainsetup() && is_engine_running() == true) {
send_chain_commands_to_engine(ECA_ENGINE::ep_c_muting, 0.0);
}
else {
selected_chainsetup_repp->toggle_chain_muting();
}
}
/**
* Toggles whether chain operators are enabled or disabled
*
* require:
* is_selected() == true && is_connected() == true
* selected_chains().size() > 0
*/
void ECA_CONTROL::toggle_chain_bypass(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() > 0);
// --------
if (connected_chainsetup() == selected_chainsetup() && is_engine_running() == true) {
send_chain_commands_to_engine(ECA_ENGINE::ep_c_bypass, 0.0);
}
else {
selected_chainsetup_repp->toggle_chain_bypass();
}
}
void ECA_CONTROL::audio_input_as_selected(void)
{
/* note, here we check that the pointer is still a valid one */
if (selected_chainsetup_repp->ok_audio_object(selected_audio_input_repp) != true)
selected_audio_input_repp = 0;
selected_audio_object_repp = selected_audio_input_repp;
}
void ECA_CONTROL::audio_output_as_selected(void)
{
/* note, here we check that the pointer is still a valid one */
if (selected_chainsetup_repp->ok_audio_object(selected_audio_output_repp) != true)
selected_audio_output_repp = 0;
selected_audio_object_repp = selected_audio_output_repp;
}
/**
* Sets default audio format. This format will be used, when
* adding audio inputs and outputs.
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::set_default_audio_format(const string& sfrm,
int channels,
long int srate,
bool interleaving)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
string format;
format = "-f:";
format += sfrm;
format += ",";
format += kvu_numtostr(channels);
format += ",";
format += kvu_numtostr(srate);
format += ",";
if (interleaving == true)
format += "i";
else
format += "n";
selected_chainsetup_repp->interpret_object_option(format);
if (selected_chainsetup_repp->interpret_result() != true) {
set_last_error(selected_chainsetup_repp->interpret_result_verbose());
}
}
/**
* Returns the default audio format.
*
* @pre is_selected() == true
*/
const ECA_AUDIO_FORMAT& ECA_CONTROL::default_audio_format(void) const
{
// --
DBC_REQUIRE(is_selected() == true);
// --
return selected_chainsetup_repp->default_audio_format();
}
/**
* Sets default audio format. This format will be used, when
* adding audio inputs and outputs.
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::set_default_audio_format(const ECA_AUDIO_FORMAT& format)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
set_default_audio_format(format.format_string(),
static_cast<int>(format.channels()),
static_cast<long int>(format.samples_per_second()),
format.interleaved_channels());
}
static AUDIO_IO* priv_select_audio_object(const std::vector<AUDIO_IO*>& objects, const std::string& name)
{
AUDIO_IO* result = 0;
/* NOTE: ugly, but needed to maintain compability with older 2.4.x
* releases that allowed double-quoted filenames to ai/ao-select */
std::string stripped_name;
if (name.size() > 0 &&
name[0] == '"') {
stripped_name = name;
kvu_string_strip_outer_quotes(&stripped_name, '"');
}
std::vector<AUDIO_IO*>::size_type p = 0;
for(p = 0; p != objects.size(); p++) {
if (objects[p]->label() == name ||
objects[p]->label() == stripped_name) {
result = objects[p];
/* note: in case 'name' is not unique, the first matching
* instance is selected */
break;
}
}
return result;
}
/**
* Selects an audio input
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::select_audio_input(const string& name)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
selected_audio_input_repp =
priv_select_audio_object(selected_chainsetup_repp->inputs, name);
}
/**
* Selects an audio output
*
* require:
* is_selected() == true
*/
void ECA_CONTROL::select_audio_output(const string& name)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
selected_audio_output_repp =
priv_select_audio_object(selected_chainsetup_repp->outputs, name);
}
/**
* Selects an audio input by index.
*
* @pre is_selected() == true
* @pre index_number > 0
*/
void ECA_CONTROL::select_audio_input_by_index(int index_number)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(index_number > 0);
// --------
selected_audio_input_repp = 0;
if (index_number <= static_cast<int>(selected_chainsetup_repp->inputs.size()))
selected_audio_input_repp = selected_chainsetup_repp->inputs[index_number-1];
}
/**
* Selects an audio output by index.
*
* @pre is_selected() == true
* @pre index_number > 0
*/
void ECA_CONTROL::select_audio_output_by_index(int index_number)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(index_number > 0);
// --------
selected_audio_output_repp = 0;
if (index_number <= static_cast<int>(selected_chainsetup_repp->outputs.size()))
selected_audio_output_repp = selected_chainsetup_repp->outputs[index_number-1];
}
/**
* Gets audio format information of the object given as argument.
* Note! To get audio format information, audio objects need
* to be opened. Because of this, object argument cannot be given
* as a const pointer.
*/
ECA_AUDIO_FORMAT ECA_CONTROL::get_audio_format(AUDIO_IO* aobj) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(aobj != 0);
// --------
bool was_open = true;
if (aobj->is_open() == false) {
was_open = false;
try {
aobj->open();
}
catch(AUDIO_IO::SETUP_ERROR&) {
// FIXME: what to do here?
}
}
ECA_AUDIO_FORMAT t (aobj->channels(),
aobj->samples_per_second(),
aobj->sample_format(),
aobj->interleaved_channels());
if (was_open == false) aobj->close();
return t;
}
/**
* Sets the default audio format to the match the currently
* select audio input's audio format.
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre selected_audio_object_repp != 0
*/
void ECA_CONTROL::set_default_audio_format_to_selected_input(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_input() != 0);
// --------
set_default_audio_format(get_audio_format(selected_audio_input_repp));
}
/**
* Sets the default audio format to the match the currently
* select audio output's audio format.
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre selected_audio_object_repp != 0
*/
void ECA_CONTROL::set_default_audio_format_to_selected_output(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_output() != 0);
// --------
set_default_audio_format(get_audio_format(selected_audio_output_repp));
}
/**
* Adds a new audio input (file, soundcard device, etc). Input
* is attached to currently selected chains (if any). If 'filename'
* doesn't exist or is otherwise invalid, no input is added.
*
* require:
* filename.empty() == false
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
*/
void ECA_CONTROL::add_audio_input(const string& filename)
{
// --------
DBC_REQUIRE(filename.empty() == false);
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
// --------
selected_audio_input_repp = 0;
selected_chainsetup_repp->interpret_object_option("-i:" + filename);
if (selected_chainsetup_repp->interpret_result() == true) {
select_audio_input(kvu_get_argument_number(1, filename));
ECA_LOG_MSG(ECA_LOGGER::info, "Added audio input \"" + filename + "\".");
}
else {
set_last_error(selected_chainsetup_repp->interpret_result_verbose());
}
}
/**
* Adds a new audio output (file, soundcard device, etc). Output
* is attached to currently selected chains (if any). If 'filename'
* doesn't exist or is otherwise invalid, no input is added.
*
* require:
* filename.empty() == false
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
*/
void ECA_CONTROL::add_audio_output(const string& filename)
{
// --------
DBC_REQUIRE(filename.empty() == false);
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
// --------
selected_audio_output_repp = 0;
selected_chainsetup_repp->interpret_object_option("-o:" + filename);
if (selected_chainsetup_repp->interpret_result() == true) {
select_audio_output(kvu_get_argument_number(1, filename));
ECA_LOG_MSG(ECA_LOGGER::info, "Added audio output \"" + filename +
"\".");
} else {
set_last_error(selected_chainsetup_repp->interpret_result_verbose());
}
}
/**
* Adds a default output (as defined in ~/.ecasoundrc) and attach
* it to currently selected chains.
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
*/
void ECA_CONTROL::add_default_output(void)
{
// --------
DBC_REQUIRE(selected_chains().size() > 0);
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
// --------
add_audio_output(ECA_OBJECT_FACTORY::probe_default_output_device());
ECA_LOG_MSG(ECA_LOGGER::info, "Added default output to selected chains.");
}
/**
* Gets a vector of all audio input names.
*
* require:
* is_selected() == true
*/
std::vector<string> ECA_CONTROL::audio_input_names(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
return selected_chainsetup_repp->audio_input_names();
}
/**
* Gets a vector of all audio output names.
*
* require:
* is_selected() == true
*/
std::vector<string> ECA_CONTROL::audio_output_names(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
return selected_chainsetup_repp->audio_output_names();
}
/**
* Gets a pointer to the currently selected audio input.
* Returns 0 if no audio object is selected.
*
* require:
* is_selected() == true
*/
const AUDIO_IO* ECA_CONTROL::get_audio_input(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
/* note, here we check that the pointer is still a valid one */
if (selected_chainsetup_repp->ok_audio_object(selected_audio_input_repp) != true)
selected_audio_input_repp = 0;
return selected_audio_input_repp;
}
/**
* Gets a pointer to the currently selected audio output.
* Returns 0 if no audio object is selected.
*
* require:
* is_selected() == true
*/
const AUDIO_IO* ECA_CONTROL::get_audio_output(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
/* note, here we check that the pointer is still a valid one */
if (selected_chainsetup_repp->ok_audio_object(selected_audio_output_repp) != true)
selected_audio_output_repp = 0;
return selected_audio_output_repp;
}
/**
* Removes the selected audio input.
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre get_audio_input() != 0
*
* @post selected_audio_input_repp = 0
*/
void ECA_CONTROL::remove_audio_input(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_input() != 0);
// --------
ECA_LOG_MSG(ECA_LOGGER::info, "Removing selected audio input \"" + selected_audio_input_repp->label() +
"\" from selected chains.");
selected_chainsetup_repp->remove_audio_input(selected_audio_input_repp->label());
selected_audio_input_repp = 0;
// --------
DBC_ENSURE(selected_audio_input_repp == 0);
// --------
}
/**
* Removes the selected audio output.
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre get_audio_output() != 0
*
* @post selected_audio_output_repp = 0
*/
void ECA_CONTROL::remove_audio_output(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_output() != 0);
// --------
ECA_LOG_MSG(ECA_LOGGER::info, "Removing selected audio output \"" + selected_audio_output_repp->label() +
"\" from selected chains.");
selected_chainsetup_repp->remove_audio_output(selected_audio_output_repp->label());
selected_audio_output_repp = 0;
// --------
DBC_ENSURE(selected_audio_output_repp == 0);
// --------
}
/**
* Attaches selected audio input to selected chains
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre get_audio_input() != 0
*/
void ECA_CONTROL::attach_audio_input(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_input() != 0);
// --------
selected_chainsetup_repp->attach_input_to_selected_chains(selected_audio_input_repp);
ECA_LOG_MSG(ECA_LOGGER::info, "Attached audio input \"" + selected_audio_input_repp->label() +
"\" to selected chains.");
}
/**
* Attaches selected audio output to selected chains
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre get_audio_output() != 0
*/
void ECA_CONTROL::attach_audio_output(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_output() != 0);
// --------
selected_chainsetup_repp->attach_output_to_selected_chains(selected_audio_output_repp);
ECA_LOG_MSG(ECA_LOGGER::info, "Attached audio output \"" + selected_audio_output_repp->label() +
"\" to selected chains.");
}
/**
* Get a string containing a comma separated list of all chains
* attached to input with index 'aiod'.
*
* @pre is_selected() == true
*/
string ECA_CONTROL::attached_chains_input(AUDIO_IO* aiod) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
vector<string> t = selected_chainsetup_repp->get_attached_chains_to_input(aiod);
string out = "";
vector<string>::const_iterator p = t.begin();
while(p != t.end()) {
out += *p;
++p;
if (p != t.end()) out += ",";
}
return out;
}
/**
* Get a string containing a comma separated list of all chains
* attached to output with index 'aiod'.
*
* @pre is_selected() == true
*/
string ECA_CONTROL::attached_chains_output(AUDIO_IO* aiod) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
vector<string> t = selected_chainsetup_repp->get_attached_chains_to_output(aiod);
string out = "";
vector<string>::const_iterator p = t.begin();
while(p != t.end()) {
out += *p;
++p;
if (p != t.end()) out += ",";
}
return out;
}
/**
* Get a string containing a comma separated list of all chains
* attached to audio object with name 'filename'.
*
* @pre is_selected() == true
*/
vector<string> ECA_CONTROL::attached_chains(const string& filename) const
{
// --------
DBC_REQUIRE(is_selected() == true);
// --------
return selected_chainsetup_repp->get_attached_chains_to_iodev(filename);
}
/**
* Rewinds selected audio object by 'pos_in_seconds' seconds
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre selected_audio_object_repp != 0
*/
void ECA_CONTROL::rewind_audio_object(double seconds)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
// --------
selected_audio_object_repp->seek_position_in_seconds(selected_audio_object_repp->position_in_seconds_exact() - seconds);
}
/**
* Forwards selected audio object by 'pos_in_seconds' seconds
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre selected_audio_object_repp != 0
*/
void ECA_CONTROL::forward_audio_object(double seconds)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
// --------
selected_audio_object_repp->seek_position_in_seconds(selected_audio_object_repp->position_in_seconds_exact() + seconds);
}
/**
* Sets position of selected audio object
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
* selected_audio_object_repp != 0
*/
void ECA_CONTROL::set_audio_object_position(double seconds)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
// --------
selected_audio_object_repp->seek_position_in_seconds(seconds);
}
/**
* Sets position of selected audio object
*
* @pre is_selected() == true
* @pre connected_chainsetup() != selected_chainsetup()
* @pre selected_audio_object_repp != 0
*/
void ECA_CONTROL::set_audio_object_position_samples(SAMPLE_SPECS::sample_pos_t samples)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
// --------
selected_audio_object_repp->seek_position_in_samples(samples);
}
/**
* Spawns an external wave editor for editing selected audio object.
*
* require:
* is_selected()
* connected_chainsetup() != selected_chainsetup()
* selected_audio_object_repp != 0
*/
void ECA_CONTROL::wave_edit_audio_object(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(connected_chainsetup() != selected_chainsetup());
DBC_REQUIRE(get_audio_input() != 0 || get_audio_output() != 0);
// --------
string name = selected_audio_object_repp->label();
int res = ::system(string(resource_value("ext-cmd-wave-editor") + " " + name).c_str());
if (res == 127 || res == -1) {
ECA_LOG_MSG(ECA_LOGGER::info, "Can't edit; unable to open wave editor \""
+ resource_value("x-wave-editor") + "\".");
}
}
/**
* Stops the engine if necessary and locks it
* down for editing in case the engine is controlled
* by an external source.
*
* @see cond_stop_for_editing()
*/
bool ECA_CONTROL::cond_stop_for_editing(void)
{
bool was_running = false;
if (selected_chainsetup() == connected_chainsetup() && is_running() == true) {
engine_repp->command(ECA_ENGINE::ep_edit_lock, 0.0);
was_running = true;
stop_on_condition();
}
return was_running;
}
/**
* Stops the engine if necessary and locks it
* down for editing in case the engine is controlled
* by an external source.
*
* @see cond_start_after_editing()
*/
void ECA_CONTROL::cond_start_after_editing(bool was_running)
{
if (is_engine_running() == true && was_running == true) {
engine_repp->command(ECA_ENGINE::ep_edit_unlock, 0.0);
engine_repp->command(ECA_ENGINE::ep_start, 0.0);
}
}
/**
* Adds a new chain operator
*
* @param gcontrol_params is an Ecasound option string describing
* a controlled: syntax is either "-<id_string>:par1,...,parN",
* or just "<id_string>:par1,...,parN"
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
void ECA_CONTROL::add_chain_operator(const string& chainop_params)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
bool was_running = cond_stop_for_editing();
if (chainop_params.size() > 0) {
if (chainop_params[0] != '-')
selected_chainsetup_repp->interpret_object_option(string("-") + chainop_params);
else
selected_chainsetup_repp->interpret_object_option(chainop_params);
if (selected_chainsetup_repp->interpret_result() != true) {
set_last_error(selected_chainsetup_repp->interpret_result_verbose());
}
}
cond_start_after_editing(was_running);
}
/**
* Adds a new chain operator. Pointer given as argument
* will remain to be usable, but notice that it is
* _NOT_ thread-safe to use assigned/registered objects
* from client programs. You must be sure that ecasound
* isn't using the same object as you are. The
* easiest way to assure this is to disconnect
* the chainsetup to which object is attached.
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
* selected_chains().size() == 1
* cotmp != 0
*/
void ECA_CONTROL::add_chain_operator(CHAIN_OPERATOR* cotmp)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(cotmp != 0);
// --------
bool was_running = cond_stop_for_editing();
selected_chainsetup_repp->add_chain_operator(cotmp);
cond_start_after_editing(was_running);
}
/**
* Returns a pointer to the the selected chain operator. If no chain
* operator is selected, 0 is returned.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
const CHAIN_OPERATOR* ECA_CONTROL::get_chain_operator(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size())
return selected_chainsetup_repp->chains[p]->get_selected_chain_operator();
return 0;
}
/**
* Returns a list of chain operator names.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
std::vector<string> ECA_CONTROL::chain_operator_names(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
std::vector<string> result;
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
int save_selected_cop = selected_chain->selected_chain_operator();
for(int n = 0;
n < selected_chain->number_of_chain_operators();
n++) {
selected_chain->select_chain_operator(n + 1);
result.push_back(selected_chain->chain_operator_name());
}
selected_chain->select_chain_operator(save_selected_cop);
}
return result;
}
/**
* Returns the index of the selected chain operator. If no chain
* operator is selected, 0 is returned.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
int ECA_CONTROL::selected_chain_operator(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size())
return selected_chainsetup_repp->chains[p]->selected_chain_operator();
return(0);
}
/**
* Removes the selected chain operator
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
* selected_chains().size() == 1
*/
void ECA_CONTROL::remove_chain_operator(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
bool was_running = cond_stop_for_editing();
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size())
selected_chainsetup_repp->chains[p]->remove_chain_operator(-1);
cond_start_after_editing(was_running);
}
/**
* Selects chain operator 'chainop_id'.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* chainop_id > 0
*/
void ECA_CONTROL::select_chain_operator(int chainop_id)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(chainop_id > 0);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
CHAIN *ch = selected_chainsetup_repp->chains[p];
if (chainop_id < ch->number_of_chain_operators() + 1) {
ch->select_chain_operator(chainop_id);
}
}
}
/**
* Returns a list of chain operator parameter names.
*
* require:
* is_selected == true
* selected_chains().size() == 1
*/
std::vector<string> ECA_CONTROL::chain_operator_parameter_names(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
std::vector<string> result;
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
if (selected_chain->selected_chain_operator() > 0) {
int save_selected_copp = selected_chain->selected_chain_operator_parameter();
for(int n = 0;
n < selected_chain->number_of_chain_operator_parameters();
n++) {
selected_chain->select_chain_operator_parameter(n + 1);
result.push_back(selected_chain->chain_operator_parameter_name());
}
selected_chain->select_chain_operator_parameter(save_selected_copp);
}
}
return result;
}
/**
* Selects chain operator parameter 'param'.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* get_chain_operator() != 0
* param > 0
*/
void ECA_CONTROL::select_chain_operator_parameter(int param)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(param > 0);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
selected_chainsetup_repp->chains[p]->select_chain_operator_parameter(param);
}
}
/**
* Sets chain operator parameter value
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* get_chain_operator() != 0
*/
void ECA_CONTROL::set_chain_operator_parameter(CHAIN_OPERATOR::parameter_t value)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(get_chain_operator() != 0);
// --------
ECA::chainsetup_edit_t edit;
edit.type = ECA::edit_cop_set_param;
edit.cs_ptr = selected_chainsetup_repp;
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
/* note: unlike all other functions, first_selected_chain()
* returns 0..N */
CHAIN *chain = selected_chainsetup_repp->chains[p];
edit.m.cop_set_param.chain = p + 1;
edit.m.cop_set_param.op = chain->selected_chain_operator();
edit.m.cop_set_param.param = chain->selected_chain_operator_parameter();
edit.m.cop_set_param.value = value;
execute_edit_on_selected(edit);
}
}
/**
* Returns the selected chain operator parameter value
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
CHAIN_OPERATOR::parameter_t ECA_CONTROL::get_chain_operator_parameter(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
if (selected_chainsetup_repp->chains[p]->selected_chain_operator() > 0 &&
selected_chainsetup_repp->chains[p]->selected_chain_operator_parameter() > 0)
return selected_chainsetup_repp->chains[p]->get_parameter();
}
return 0.0f;
}
/**
* Returns the index number of selected chain operator parameter.
* If no parameter is selected, 0 is returned.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* get_chain_operator() != 0
*/
int ECA_CONTROL::selected_chain_operator_parameter(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(get_chain_operator() != 0);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
return selected_chainsetup_repp->chains[p]->selected_chain_operator_parameter();
}
return 0;
}
/**
* Adds a new controller
*
* @param gcontrol_params is an Ecasound option string describing
* a controlled: syntax is either "-<id_string>:par1,...,parN",
* or just "<id_string>:par1,...,parN"
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
* selected_chains().size() > 0
*/
void ECA_CONTROL::add_controller(const string& gcontrol_params)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() > 0);
// --------
bool was_running = cond_stop_for_editing();
if (gcontrol_params.size() > 0) {
if (gcontrol_params[0] != '-')
selected_chainsetup_repp->interpret_object_option(string("-") + gcontrol_params);
else
selected_chainsetup_repp->interpret_object_option(gcontrol_params);
if (selected_chainsetup_repp->interpret_result() != true) {
set_last_error(selected_chainsetup_repp->interpret_result_verbose());
}
}
cond_start_after_editing(was_running);
}
/**
* Selects the Nth controller.
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
* selected_chains().size() == 1
* controller_id > 0
*/
void ECA_CONTROL::select_controller(int controller_id)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(controller_id > 0);
// --------
bool was_running = cond_stop_for_editing();
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
selected_chainsetup_repp->chains[p]->select_controller(controller_id);
}
cond_start_after_editing(was_running);
}
/**
* Removes the selected controller.
*
* require:
* is_selected() == true
* connected_chainsetup() != selected_chainsetup()
* selected_chains().size() == 1
* get_controller() != 0
*/
void ECA_CONTROL::remove_controller(void)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(get_controller() != 0);
// --------
bool was_running = cond_stop_for_editing();
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
selected_chainsetup_repp->chains[p]->remove_controller();
}
cond_start_after_editing(was_running);
}
/**
* Returns a list of controller names.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
std::vector<string> ECA_CONTROL::controller_names(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
std::vector<string> result;
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
int save_selected_ctrl = selected_chain->selected_controller();
for(int n = 0;
n < selected_chain->number_of_controllers();
n++) {
selected_chain->select_controller(n + 1);
result.push_back(selected_chain->controller_name());
}
selected_chain->select_controller(save_selected_ctrl);
}
return result;
}
/**
* Returns a pointer to the selected controller. If no controller is
* selected, 0 is returned.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
const GENERIC_CONTROLLER* ECA_CONTROL::get_controller(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size())
return selected_chainsetup_repp->chains[p]->get_selected_controller();
return 0;
}
/**
* Returns the index number of the selected controller. If no controller is
* selected, 0 is returned.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
int ECA_CONTROL::selected_controller(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size())
return selected_chainsetup_repp->chains[p]->selected_controller();
return 0;
}
/**
* Returns a list of the selected controller's parameter names
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* get_controller() != 0
*/
std::vector<string> ECA_CONTROL::controller_parameter_names(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(get_controller() != 0);
// --------
std::vector<string> result;
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
int save_selected_ctrlp = selected_chain->selected_controller_parameter();
for(int n = 0;
n < selected_chain->number_of_controller_parameters();
n++) {
selected_chain->select_controller_parameter(n + 1);
result.push_back(selected_chain->controller_parameter_name());
}
selected_chain->select_controller_parameter(save_selected_ctrlp);
}
return result;
}
/**
* Select a particular controller parameter
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* param > 0
*/
void ECA_CONTROL::select_controller_parameter(int param)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(param > 0);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
selected_chainsetup_repp->chains[p]->select_controller_parameter(param);
}
}
/**
* Returns the index number of selected controller parameter.
* If no parameter is selected, 0 is returned.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* get_controller() != 0
*/
int ECA_CONTROL::selected_controller_parameter(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(get_controller() != 0);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
return selected_chainsetup_repp->chains[p]->selected_controller_parameter();
}
return 0;
}
/**
* Set the currently selected controller parameter
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* get_controller() != 0
*/
void ECA_CONTROL::set_controller_parameter(CHAIN_OPERATOR::parameter_t value)
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(get_controller() != 0);
// --------
ECA::chainsetup_edit_t edit;
edit.type = ECA::edit_ctrl_set_param;
edit.cs_ptr = selected_chainsetup_repp;
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
/* note: unlike all other functions, first_selected_chain()
* returns 0..N */
CHAIN *chain = selected_chainsetup_repp->chains[p];
edit.m.ctrl_set_param.chain = p + 1;
edit.m.ctrl_set_param.op = chain->selected_controller();
edit.m.ctrl_set_param.param = chain->selected_controller_parameter();
edit.m.ctrl_set_param.value = value;
execute_edit_on_selected(edit);
}
}
/**
* Returns the value of the currently selected controller parameter
* If no controller or controller parameter is selected, 0.0 is returned.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
*/
CONTROLLER_SOURCE::parameter_t ECA_CONTROL::get_controller_parameter(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
// --------
unsigned int p = selected_chainsetup_repp->first_selected_chain();
if (p < selected_chainsetup_repp->chains.size()) {
if (selected_chainsetup_repp->chains[p]->selected_controller() > 0 &&
selected_chainsetup_repp->chains[p]->selected_controller_parameter() > 0)
return selected_chainsetup_repp->chains[p]->get_controller_parameter();
}
return 0.0f;
}
/**
* Returns the index number of chain operator that is the target for the currently selected
* controller.
*
* require:
* is_selected() == true
* selected_chains().size() == 1
* get_controller() != 0
*/
int ECA_CONTROL::selected_controller_target(void) const
{
// --------
DBC_REQUIRE(is_selected() == true);
DBC_REQUIRE(selected_chains().size() == 1);
DBC_REQUIRE(get_controller() != 0);
// --------
/*
We find the index of the chain_op that corresponds to the the selected controller's target
by looping through the chain ops and comparing the value of the chain operator (a CHAIN_OPERATOR*)
with the value of the controllers "target_pointer()".
*/
unsigned int p = selected_chainsetup_repp->first_selected_chain();
int result = 0;
if (p < selected_chainsetup_repp->chains.size()) {
CHAIN* selected_chain = selected_chainsetup_repp->chains[p];
OPERATOR* target = selected_chain->get_selected_controller()->target_pointer();
for(int n = 0;
n < selected_chain->number_of_chain_operators();
n++) {
if (selected_chain->get_chain_operator(n) == target) {
result = n+1;
break;
}
}
}
return result;
}