sintonia/library/ecasound-2.7.2/libecasound/eca-chainsetup-parser.cpp

1245 lines
33 KiB
C++

// ------------------------------------------------------------------------
// eca-chainsetup-parser.cpp: Functionality for parsing chainsetup
// option syntax.
// Copyright (C) 2001-2006 Kai Vehmanen
//
// Attributes:
// eca-style-version: 3
//
// 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
// ------------------------------------------------------------------------
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <algorithm> /* find() */
#include <kvu_dbc.h> /* DBC_* */
#include <kvu_message_item.h>
#include <kvu_numtostr.h>
#include <kvu_utils.h>
#include "audioio.h"
#include "file-preset.h"
#include "global-preset.h"
#include "midiio.h"
#include "midi-client.h"
#include "midi-server.h"
#include "generic-controller.h"
#include "eca-chain.h"
#include "eca-logger.h"
#include "eca-object-factory.h"
#include "eca-preset-map.h"
#include "eca-chainsetup.h"
#include "eca-chainsetup-parser.h"
#include "eca-chainsetup-bufparams.h"
using std::string;
ECA_CHAINSETUP_PARSER::ECA_CHAINSETUP_PARSER(ECA_CHAINSETUP* csetup)
: csetup_repp(csetup),
last_audio_add_vector_repp(0)
{
}
/**
* Interprets one option. This is the most generic variant of
* the interpretation routines; both global and object specific
* options are handled.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
*
* @post (option succesfully interpreted && interpret_result() == true) ||
* (unknown or invalid option && interpret_result() != true)
*/
void ECA_CHAINSETUP_PARSER::interpret_option (const string& arg)
{
interpret_entry();
istatus_rep = false;
interpret_global_option(arg);
if (istatus_rep != true) interpret_object_option(arg);
interpret_exit(arg);
}
/**
* Interprets one option. All non-global options are ignored. Global
* options can be interpreted multiple times and in any order.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
* @post (option succesfully interpreted && interpretation_result() == true) ||
* (unknown or invalid option && interpretation_result() == false)
*/
void ECA_CHAINSETUP_PARSER::interpret_global_option (const string& arg)
{
interpret_entry();
ECA_LOG_MSG(ECA_LOGGER::system_objects, "Interpreting global option \"" + arg + "\".");
if (istatus_rep == false) interpret_general_option(arg);
if (istatus_rep == false) interpret_processing_control(arg);
if (istatus_rep == false) interpret_chains(arg);
interpret_exit(arg);
}
/**
* Interprets one option. All options not directly related to
* ecasound objects are ignored.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
*
* @post (option succesfully interpreted && interpretation_result() == true) ||
* (unknown or invalid option && interpretation_result() == false)
*/
void ECA_CHAINSETUP_PARSER::interpret_object_option (const string& arg)
{
interpret_entry();
ECA_LOG_MSG(ECA_LOGGER::system_objects, "Interpreting object option \"" + arg + "\".");
interpret_chains(arg);
if (istatus_rep == false) interpret_audio_format(arg);
if (istatus_rep == false) interpret_audioio_device(arg);
if (istatus_rep == false) interpret_audioio_manager(arg);
if (istatus_rep == false) interpret_midi_device(arg);
if (istatus_rep == false) interpret_chain_operator(arg);
if (istatus_rep == false) interpret_controller(arg);
interpret_exit(arg);
}
/**
* Interpret a vector of options.
*/
void ECA_CHAINSETUP_PARSER::interpret_options(const std::vector<string>& opts)
{
int optcount = static_cast<int>(opts.size());
int global_matches = 0;
int other_matches = 0;
interpret_set_result(true, ""); /* if opts.size() == 0 */
/*
* phase1: parse global options only */
std::vector<string>::const_iterator p = opts.begin();
while(p != opts.end()) {
interpret_global_option(*p);
/* note! below we make sure we don't calculate chain
* definitions twice */
if (interpret_match_found() == true &&
!((*p)[0] == '-' && (*p)[1] == 'a')) global_matches++;
++p;
}
if (csetup_repp->chains.size() == 0) csetup_repp->add_default_chain();
/*
* phase2: parse all options, including processing
* the global options again */
p = opts.begin();
while(p != opts.end()) {
interpret_object_option(*p);
if (interpret_match_found() == true) {
other_matches++;
if (interpret_result() != true) {
/* invalid option format */
break;
}
}
else {
/* hack to avoid printing the same info multiple times */
int dlevel = ECA_LOGGER::instance().get_log_level_bitmask();
ECA_LOGGER::instance().disable();
interpret_global_option(*p);
ECA_LOGGER::instance().set_log_level_bitmask(dlevel);
if (interpret_match_found() != true) {
interpret_set_result(false, string("Invalid argument, unable to parse: \"") + *p + "\"");
break;
}
else {
if (interpret_result() != true) {
/* invalid option format */
break;
}
}
}
++p;
}
if (other_matches + global_matches != optcount) {
ECA_LOG_MSG(ECA_LOGGER::info,
string("WARNING: Only ") +
kvu_numtostr(other_matches) +
"+" +
kvu_numtostr(global_matches) +
" of the expected " +
kvu_numtostr(optcount) +
" parameters were recognized succesfully.");
}
}
void ECA_CHAINSETUP_PARSER::reset_interpret_status(void) {
istatus_rep = false;
}
/**
* Preprocesses a set of options.
*
* Notes! See also ECA_SESSION::preprocess_options()
*
* @post all options valid for interpret_option()
*/
void ECA_CHAINSETUP_PARSER::preprocess_options(std::vector<string>& opts) const
{
std::vector<string>::iterator p = opts.begin();
while(p != opts.end()) {
/* handle options not starting with an '-' sign */
if (p->size() > 0 && (*p)[0] != '-') {
/* hack1: rest as "-i:file" */
ECA_LOG_MSG(ECA_LOGGER::info, "NOTE: Interpreting option " +
*p +
" as -i:" +
*p +
".");
*p = "-i:" + *p;
}
++p;
}
}
/**
* Resets the interpretation logic.
*
* @post interpret_status() != true
*/
void ECA_CHAINSETUP_PARSER::interpret_entry(void)
{
istatus_rep = false;
interpret_set_result(true, "");
DBC_ENSURE(interpret_match_found() != true);
}
/**
* Exits the interpretation logic.
*
* @post interpret_result() == true && interpret_result_verbose() == "" ||
* interpret_result() == false && interpret_result_verbose() != ""
*/
void ECA_CHAINSETUP_PARSER::interpret_exit(const string& arg)
{
if (istatus_rep != true) {
/* option 'arg' was not found */
interpret_set_result(false, string("Interpreting option \"") +
arg +
"\" failed.");
}
else {
/* option 'arg' was found, but incorrect */
if (interpret_result() != true) {
if (interpret_result_verbose() == "") {
interpret_set_result(false, string("Interpreting option \"") +
arg +
"\" failed.");
}
/* else -> otherwise error code is already set */
}
}
DBC_ENSURE((interpret_result() == true && interpret_result_verbose() == "") ||
(interpret_result() == false && interpret_result_verbose() != ""));
}
/**
* Handle general options.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
* @pre istatus_rep == false
*/
void ECA_CHAINSETUP_PARSER::interpret_general_option (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
DBC_REQUIRE(csetup_repp->is_enabled() != true);
// --------
bool match = true;
if (argu.size() < 2) return;
switch(argu[1]) {
case 'b':
{
int bsize = atoi(kvu_get_argument_number(1, argu).c_str());
if (bsize > 0) {
csetup_repp->set_buffersize(bsize);
MESSAGE_ITEM mitemb;
mitemb << "Setting buffersize to (samples) " << bsize << ".";
ECA_LOG_MSG(ECA_LOGGER::info, mitemb.to_string());
}
else {
ECA_LOG_MSG(ECA_LOGGER::info, "Invalid buffersize given; using default value.");
}
break;
}
case 'B':
{
string temp = kvu_get_argument_number(1, argu);
if (temp == "auto") {
csetup_repp->set_buffering_mode(ECA_CHAINSETUP::cs_bmode_auto);
ECA_LOG_MSG(ECA_LOGGER::info, "Buffering mode is selected automatically.");
}
else if (temp == "nonrt") {
csetup_repp->set_buffering_mode(ECA_CHAINSETUP::cs_bmode_nonrt);
ECA_LOG_MSG(ECA_LOGGER::info, "Buffering mode 'nonrt' selected.");
}
else if (temp == "rt") {
csetup_repp->set_buffering_mode(ECA_CHAINSETUP::cs_bmode_rt);
ECA_LOG_MSG(ECA_LOGGER::info, "Buffering mode 'rt' selected.");
}
else if (temp == "rtlowlatency") {
csetup_repp->set_buffering_mode(ECA_CHAINSETUP::cs_bmode_rtlowlatency);
ECA_LOG_MSG(ECA_LOGGER::info, "Buffering mode 'rtlowlatency' selected.");
}
else {
csetup_repp->set_buffering_mode(ECA_CHAINSETUP::cs_bmode_auto);
ECA_LOG_MSG(ECA_LOGGER::info, "Unknown buffering mode; 'auto' mode is used instead.");
}
break;
}
case 'n':
{
csetup_repp->set_name(kvu_get_argument_number(1, argu));
ECA_LOG_MSG(ECA_LOGGER::info, "Setting chainsetup name to \""
+ csetup_repp->name() + "\".");
break;
}
case 'r':
{
int prio = ::atoi(kvu_get_argument_number(1, argu).c_str());
if (prio < 0) {
ECA_LOG_MSG(ECA_LOGGER::info, "Raised-priority mode disabled.");
csetup_repp->toggle_raised_priority(false);
}
else {
if (prio == 0) prio = 50;
csetup_repp->set_sched_priority(prio);
ECA_LOG_MSG(ECA_LOGGER::info, "Raised-priority mode enabled. (prio:" +
kvu_numtostr(prio) + ")");
csetup_repp->toggle_raised_priority(true);
}
break;
}
case 's':
{
if (argu.size() > 2 && argu[2] == 'r') {
ECA_LOG_MSG(ECA_LOGGER::info, "Option '-sr' is obsolete. Use syntax '-f:sfmt,channels,srate,ileaving' instead.");
}
break;
}
case 'x':
{
ECA_LOG_MSG(ECA_LOGGER::info, "Truncating outputs (overwrite-mode).");
csetup_repp->set_output_openmode(AUDIO_IO::io_write);
break;
}
case 'X':
{
ECA_LOG_MSG(ECA_LOGGER::info, "Updating outputs (rw-mode).");
csetup_repp->set_output_openmode(AUDIO_IO::io_readwrite);
break;
}
case 'z':
{
string first_arg (kvu_get_argument_number(1, argu));
if (first_arg == "db") {
long int bufs = atol(kvu_get_argument_number(2, argu).c_str());
if (bufs == 0) bufs = 100000;
csetup_repp->set_double_buffer_size(bufs);
ECA_LOG_MSG(ECA_LOGGER::info, "Using double-buffer of " +
kvu_numtostr(bufs) + " sample frames.");
csetup_repp->toggle_double_buffering(true);
}
else if (first_arg == "nodb") {
ECA_LOG_MSG(ECA_LOGGER::info, "Double-buffering disabled.");
csetup_repp->toggle_double_buffering(false);
}
else if (first_arg == "intbuf") {
ECA_LOG_MSG(ECA_LOGGER::info, "Enabling extra buffering on realtime devices.");
csetup_repp->toggle_max_buffers(true);
}
else if (first_arg == "nointbuf") {
ECA_LOG_MSG(ECA_LOGGER::info, "Disabling extra buffering on realtime devices.");
csetup_repp->toggle_max_buffers(false);
}
else if (first_arg == "multitrack") {
ECA_LOG_MSG(ECA_LOGGER::info, "Enabling multitrack-mode (override).");
long int samples = -1;
if (kvu_get_number_of_arguments(argu) > 1) {
/* -z:multitrack,XXX */
samples = atol(kvu_get_argument_number(2, argu).c_str());
}
csetup_repp->multitrack_mode_offset_rep = samples;
csetup_repp->multitrack_mode_override_rep = true;
csetup_repp->multitrack_mode_rep = true;
}
else if (first_arg == "nomultitrack") {
ECA_LOG_MSG(ECA_LOGGER::info, "Disabling multitrack-mode (override).");
csetup_repp->multitrack_mode_override_rep = true;
csetup_repp->multitrack_mode_offset_rep = 0;
csetup_repp->multitrack_mode_rep = false;
}
else if (first_arg == "psr") {
ECA_LOG_MSG(ECA_LOGGER::info, "Enabling precise-sample-rates with OSS audio devices.");
csetup_repp->toggle_precise_sample_rates(true);
}
else if (first_arg == "nopsr") {
ECA_LOG_MSG(ECA_LOGGER::info, "Disabling precise-sample-rates with OSS audio devices.");
csetup_repp->toggle_precise_sample_rates(false);
}
else if (first_arg == "xruns") {
ECA_LOG_MSG(ECA_LOGGER::info, "Processing is stopped if an xrun occurs.");
csetup_repp->toggle_ignore_xruns(false);
}
else if (first_arg == "noxruns") {
ECA_LOG_MSG(ECA_LOGGER::info, "Ignoring xruns during processing.");
csetup_repp->toggle_ignore_xruns(true);
}
else if (first_arg == "mixmode") {
if (kvu_get_argument_number(2, argu) == "sum") {
ECA_LOG_MSG(ECA_LOGGER::info, "Enabling 'sum' mixmode.");
csetup_repp->set_mix_mode(ECA_CHAINSETUP::cs_mmode_sum);
}
else {
ECA_LOG_MSG(ECA_LOGGER::info, "Enabling 'avg' mixmode.");
csetup_repp->set_mix_mode(ECA_CHAINSETUP::cs_mmode_avg);
}
}
break;
}
default: { match = false; }
}
if (match == true) istatus_rep = true;
}
/**
* Handle processing control
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
* @pre istatus_rep == false
*/
void ECA_CHAINSETUP_PARSER::interpret_processing_control (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
bool match = true;
if (argu.size() < 2) return;
switch(argu[1]) {
case 't':
{
if (argu.size() < 3) return;
switch(argu[2]) {
case ':':
{
/* note! here we set the _maximum_ length of the chainsetup */
csetup_repp->set_max_length_in_seconds(atof(kvu_get_argument_number(1, argu).c_str()));
ECA_LOG_MSG(ECA_LOGGER::info, "Set processing time to "
+ kvu_numtostr(csetup_repp->max_length_in_seconds_exact()) + ".");
break;
}
case 'l':
{
csetup_repp->toggle_looping(true);
if (csetup_repp->max_length_set() != true)
ECA_LOG_MSG(ECA_LOGGER::info, "Looping enabled. Length of input objects will be used to set the loop point.");
else
ECA_LOG_MSG(ECA_LOGGER::info, "Looping enabled.");
break;
}
}
break;
}
default: { match = false; }
}
if (match == true) istatus_rep = true;
}
/**
* Handle chain options.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
* @pre istatus_rep == false
*/
void ECA_CHAINSETUP_PARSER::interpret_chains (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
bool match = true;
if (argu.size() < 2) return;
switch(argu[1]) {
case 'a':
{
DBC_CHECK(csetup_repp->is_enabled() != true);
std::vector<string> schains = kvu_get_arguments(argu);
if (std::find(schains.begin(), schains.end(), "all") != schains.end()) {
csetup_repp->select_all_chains();
ECA_LOG_MSG(ECA_LOGGER::system_objects, "Selected all chains.");
}
else {
csetup_repp->select_chains(schains);
csetup_repp->add_new_chains(schains);
MESSAGE_ITEM mtempa;
mtempa << "Selected chain ids: ";
for (std::vector<string>::const_iterator p = schains.begin(); p !=
schains.end(); p++) { mtempa << *p << " "; }
ECA_LOG_MSG(ECA_LOGGER::system_objects, mtempa.to_string());
}
break;
}
default: { match = false; }
}
if (match == true) istatus_rep = true;
}
/**
* Handle chainsetup options.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
* @pre istatus_rep == false
*/
void ECA_CHAINSETUP_PARSER::interpret_audio_format (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
bool match = true;
if (argu.size() < 2) return;
switch(argu[1]) {
case 'f':
{
ECA_AUDIO_FORMAT active_sinfo;
int channels = atoi(kvu_get_argument_number(2, argu).c_str());
long int srate = atol(kvu_get_argument_number(3, argu).c_str());
string sample_fmt =
kvu_get_argument_number(1, argu);
/* initialize to current defaults */
active_sinfo.set_audio_format(csetup_repp->default_audio_format());
try {
if (sample_fmt.size() > 0)
active_sinfo.set_sample_format_string(sample_fmt);
}
catch(ECA_ERROR& e) {
interpret_set_result(false,
string("Unable to parse sample format \"") +
sample_fmt + "\" passed to -f.");
istatus_rep = true;
return;
}
if (channels > 0)
active_sinfo.set_channels(channels);
if (srate > 0)
active_sinfo.set_samples_per_second(srate);
if (kvu_get_argument_number(4, argu) == "n")
active_sinfo.toggle_interleaved_channels(false);
else
active_sinfo.toggle_interleaved_channels(true);
/* modify the defaults */
csetup_repp->set_default_audio_format(active_sinfo);
MESSAGE_ITEM ftemp;
ftemp << "Changed active format to (bits/channels/srate/interleave): ";
ftemp << csetup_repp->default_audio_format().format_string()
<< "/" << csetup_repp->default_audio_format().channels()
<< "/" << csetup_repp->default_audio_format().samples_per_second();
if (csetup_repp->default_audio_format().interleaved_channels() == true) {
ftemp << "/i";
}
else {
ftemp << "/n";
}
ECA_LOG_MSG(ECA_LOGGER::user_objects, ftemp.to_string());
break;
}
default: { match = false; }
}
if (match == true) istatus_rep = true;
}
/**
* Handle effect preset options.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
* @pre istatus_rep == false
*/
void ECA_CHAINSETUP_PARSER::interpret_effect_preset (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
bool match = true;
if (argu.size() < 2) return;
switch(argu[1]) {
case 'p':
{
ECA_LOG_MSG(ECA_LOGGER::system_objects, "Interpreting preset \"" + argu + "\".");
CHAIN_OPERATOR* cop = 0;
if (csetup_repp->selected_chainids.size() != 1) {
ECA_LOG_MSG(ECA_LOGGER::info,
"ERROR: Exactly one chain should be selected when adding chain operators.");
match = false;
}
if (argu.size() < 3) return;
switch(argu[2]) {
case 'f':
{
#ifndef ECA_DISABLE_EFFECTS
cop = dynamic_cast<CHAIN_OPERATOR*>(new FILE_PRESET(kvu_get_argument_number(1,argu)));
#endif
break;
}
case 'n':
{
#ifndef ECA_DISABLE_EFFECTS
string name = kvu_get_argument_number(1,argu);
const PRESET* preset = dynamic_cast<const PRESET*>(ECA_OBJECT_FACTORY::preset_map().object(name));
if (preset != 0)
cop = dynamic_cast<CHAIN_OPERATOR*>(preset->new_expr());
else
cop = 0;
#endif
break;
}
default: { }
}
if (cop != 0) {
for(int n = 0; n < cop->number_of_params(); n++) {
cop->set_parameter(n + 1, atof(kvu_get_argument_number(n + 2, argu).c_str()));
}
csetup_repp->add_chain_operator(cop);
}
break;
}
default: { match = false; }
}
if (match == true) istatus_rep = true;
}
/**
* Handle audio-IO-devices and files.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
*/
void ECA_CHAINSETUP_PARSER::interpret_audioio_device (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
string tname = kvu_get_argument_number(1, argu);
bool match = true;
bool print_error = false;
if (argu.size() < 2) return;
switch(argu[1]) {
case 'i':
{
DBC_CHECK(csetup_repp->is_enabled() != true);
AUDIO_IO* audio_input = ECA_OBJECT_FACTORY::create_audio_object(argu);
if (audio_input == 0)
audio_input = ECA_OBJECT_FACTORY::create_loop_input(argu, &csetup_repp->loop_map);
if (audio_input != 0) {
if ((audio_input->supported_io_modes() &
AUDIO_IO::io_read) != AUDIO_IO::io_read) {
interpret_set_result(false,
string("Audio object \"") +
tname +
"\" cannot be opened for input.");
}
else {
ECA_LOG_MSG(ECA_LOGGER::system_objects,"adding file \"" + tname + "\".");
csetup_repp->add_input(audio_input);
last_audio_add_vector_repp = &csetup_repp->inputs; /* for -y parsing */
}
}
else {
print_error = true;
}
break;
}
case 'o':
{
DBC_CHECK(csetup_repp->is_enabled() != true);
AUDIO_IO* audio_output = ECA_OBJECT_FACTORY::create_audio_object(argu);
if (audio_output == 0) audio_output = ECA_OBJECT_FACTORY::create_loop_output(argu, &csetup_repp->loop_map);
if (audio_output != 0) {
bool truncate = false;
int mode_tmp = csetup_repp->output_openmode();
if (mode_tmp == AUDIO_IO::io_readwrite) {
if ((audio_output->supported_io_modes() &
AUDIO_IO::io_readwrite) != AUDIO_IO::io_readwrite) {
mode_tmp = AUDIO_IO::io_write;
truncate = true;
}
}
else {
truncate = true;
}
if (((audio_output->supported_io_modes() & mode_tmp) != mode_tmp)) {
interpret_set_result(false, string("io_write/io_readwrite access modes not supported by output \"") + audio_output->name() + "\".");
}
else {
ECA_LOG_MSG(ECA_LOGGER::system_objects,"adding file \"" + tname + "\".");
csetup_repp->add_output(audio_output, truncate);
last_audio_add_vector_repp = &csetup_repp->outputs; /* for -y parsing */
}
}
else {
print_error = true;
}
break;
}
case 'y':
{
DBC_CHECK(csetup_repp->is_enabled() != true);
if (last_audio_add_vector_repp == 0) {
ECA_LOG_MSG(ECA_LOGGER::info,
"ERROR: Non-existant last audio object.");
}
else {
AUDIO_IO* last_object = (*last_audio_add_vector_repp).back();
double newpos = atof(kvu_get_argument_number(1, argu).c_str());
if (newpos > 0.0f &&
last_object &&
last_object->supports_seeking() != true) {
interpret_set_result(false, string("Audio object does not support seeking, unable to set a non-zero starting offset. Object generating the error is \"") + last_object->name() + "\".");
}
else {
last_object->seek_position_in_seconds(newpos);
if (last_object->io_mode() == AUDIO_IO::io_read) {
csetup_repp->input_start_pos[csetup_repp->input_start_pos.size() - 1] = last_object->position_in_seconds_exact();
}
else {
csetup_repp->output_start_pos[csetup_repp->output_start_pos.size() - 1] = last_object->position_in_seconds_exact();
}
ECA_LOG_MSG(ECA_LOGGER::info, "Setting starting position for audio object \""
+ last_object->label()
+ "\": "
+ kvu_numtostr(last_object->position_in_seconds_exact())
+ " seconds.");
}
break;
}
}
default: { match = false; }
}
if (match == true) istatus_rep = true;
if (print_error == true) {
interpret_set_result(false,
string("Audio object \"") +
tname +
"\" does not match any of the known audio device types or "
"file formats. You can check the list of supported "
"audio object types by issuing the command 'aio-register' in "
"ecasound's interactive mode.");
}
}
/**
* Handles audio-IO manager options.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
*/
void ECA_CHAINSETUP_PARSER::interpret_audioio_manager(const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
string tname = kvu_get_argument_number(1, argu);
bool match = true;
if (argu.size() < 2) return;
switch(argu[1]) {
case 'G':
{
DBC_CHECK(csetup_repp->is_enabled() != true);
std::vector<string> args = kvu_get_arguments(argu);
args.erase(args.begin());
DBC_CHECK(args.size() == kvu_get_arguments(argu).size() - 1);
csetup_repp->set_audio_io_manager_option(tname,
kvu_vector_to_string(args, ","));
break;
}
default: { match = false; }
}
if (match == true) istatus_rep = true;
}
/**
* Handles MIDI-IO devices.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
*/
void ECA_CHAINSETUP_PARSER::interpret_midi_device (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
bool match = true;
if (argu.size() < 2) return;
switch(argu[1]) {
case 'M':
{
if (argu.size() < 3) return;
switch(argu[2]) {
case 'd':
{
string tname = kvu_get_argument_number(1, argu);
ECA_LOG_MSG(ECA_LOGGER::system_objects,"MIDI-config: Adding device \"" + tname + "\".");
MIDI_IO* mdev = 0;
mdev = ECA_OBJECT_FACTORY::create_midi_device(argu);
if (mdev != 0) {
if ((mdev->supported_io_modes() & MIDI_IO::io_readwrite) == MIDI_IO::io_readwrite) {
mdev->io_mode(MIDI_IO::io_readwrite);
csetup_repp->add_midi_device(mdev);
csetup_repp->midi_server_needed_rep = true;
}
else {
ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: I/O-mode 'io_readwrite' not supported by MIDI-device " + mdev->name());
}
}
break;
}
case 'm':
{
if (argu.size() < 4) return;
switch(argu[3]) {
case 'r':
{
// FIXME: not implemented!
int id = atoi(kvu_get_argument_number(1, argu).c_str());
ECA_LOG_MSG(ECA_LOGGER::info,
"MIDI-config: Receiving MMC messages with id \"" +
kvu_numtostr(id) +
"\".");
csetup_repp->midi_server_repp->set_mmc_receive_id(id);
csetup_repp->midi_server_needed_rep = true;
break;
}
case 's':
{
int id = atoi(kvu_get_argument_number(1, argu).c_str());
ECA_LOG_MSG(ECA_LOGGER::info,
"MIDI-config: Adding MMC-send to device id \"" +
kvu_numtostr(id) +
"\".");
csetup_repp->midi_server_repp->add_mmc_send_id(id);
csetup_repp->midi_server_needed_rep = true;
break;
}
}
break;
}
case 's':
{
if (argu.size() < 4) return;
switch(argu[3]) {
case 'r':
{
// FIXME: not implemented
ECA_LOG_MSG(ECA_LOGGER::info,
"MIDI-config: Receiving MIDI-sync.");
csetup_repp->midi_server_needed_rep = true;
csetup_repp->midi_server_repp->toggle_midi_sync_receive(true);
break;
}
case 's':
{
// FIXME: not implemented
ECA_LOG_MSG(ECA_LOGGER::info,
"MIDI-config: Sending MIDI-sync.");
csetup_repp->midi_server_repp->toggle_midi_sync_send(true);
csetup_repp->midi_server_needed_rep = true;
break;
}
}
break;
}
}
break;
}
default: { match = false; }
}
if (match == true) istatus_rep = true;
return;
}
/**
* Handle chain operator options (chain operators, presets
* and plugins)
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
* @pre istatus_rep == false
*/
void ECA_CHAINSETUP_PARSER::interpret_chain_operator (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
CHAIN_OPERATOR* t = ECA_OBJECT_FACTORY::create_chain_operator(argu);
if (t == 0) t = ECA_OBJECT_FACTORY::create_ladspa_plugin(argu);
if (t != 0) {
if (csetup_repp->selected_chainids.size() == 1) {
csetup_repp->add_chain_operator(t);
istatus_rep = true;
}
else {
ECA_LOG_MSG(ECA_LOGGER::info,
"ERROR: Exactly one chain should be selected when adding chain operators.");
delete t;
}
}
else
interpret_effect_preset(argu);
}
/**
* Handle controller sources and general controllers.
*
* @pre argu.size() > 0
* @pre argu[0] == '-'
* @pre istatus_rep == false
*/
void ECA_CHAINSETUP_PARSER::interpret_controller (const string& argu)
{
// --------
DBC_REQUIRE(argu.size() > 0);
DBC_REQUIRE(argu[0] == '-');
DBC_REQUIRE(istatus_rep == false);
// --------
string prefix = kvu_get_argument_prefix(argu);
if (prefix == "kx") {
csetup_repp->set_target_to_controller();
ECA_LOG_MSG(ECA_LOGGER::system_objects, "Selected controllers as parameter control targets.");
istatus_rep = true;
}
else {
GENERIC_CONTROLLER* t = ECA_OBJECT_FACTORY::create_controller(argu);
if (t != 0) {
if (csetup_repp->selected_chainids.size() != 1) {
ECA_LOG_MSG(ECA_LOGGER::info,
"ERROR: Exactly one chain should be selected when adding controllers.");
delete t;
}
else {
MIDI_CLIENT* p = dynamic_cast<MIDI_CLIENT*>(t->source_pointer());
if (p != 0) {
csetup_repp->midi_server_needed_rep = true;
p->register_server(csetup_repp->midi_server_repp);
}
csetup_repp->add_controller(t);
istatus_rep = true;
}
}
}
}
string ECA_CHAINSETUP_PARSER::general_options_to_string(void) const
{
MESSAGE_ITEM t;
int setparams = csetup_repp->override_buffering_parameters().number_of_set();
ECA_LOG_MSG(ECA_LOGGER::system_objects,
"genopts tostring - " + kvu_numtostr(setparams) +
" overridden parameters.");
if (setparams > 0) {
t << "-b:" << csetup_repp->buffersize();
if (csetup_repp->raised_priority() == true)
t << " -r:" << csetup_repp->get_sched_priority();
else
t << " -r:-1";
if (csetup_repp->max_buffers() == true)
t << " -z:intbuf";
else
t << " -z:nointbuf";
if (csetup_repp->double_buffering() == true)
t << " -z:db," << csetup_repp->double_buffer_size();
else
t << " -z:nodb";
}
else {
ECA_CHAINSETUP::Buffering_mode_t bmode =
csetup_repp->buffering_mode_rep;
if (csetup_repp->active_buffering_mode_rep != ECA_CHAINSETUP::cs_bmode_none)
bmode = csetup_repp->active_buffering_mode_rep;
switch(bmode)
{
case ECA_CHAINSETUP::cs_bmode_nonrt:
{
t << "-B:nonrt";
break;
}
case ECA_CHAINSETUP::cs_bmode_rt:
{
t << "-B:rt";
break;
}
case ECA_CHAINSETUP::cs_bmode_rtlowlatency:
{
t << "-B:rtlowlatency";
break;
}
default:
{
t << " -B:auto";
}
}
}
t << " -n:\"" << csetup_repp->name() << "\"";
if (csetup_repp->output_openmode() == AUDIO_IO::io_write)
t << " -x";
else
t << " -X";
if (csetup_repp->multitrack_mode_override_rep == true) {
if (csetup_repp->multitrack_mode() == true) {
t << "-z:multitrack";
if (csetup_repp->multitrack_mode_offset_rep != -1) {
t << "," << csetup_repp->multitrack_mode_offset_rep;
}
}
else {
t << "-z:nomultitrack";
}
}
if (csetup_repp->ignore_xruns() == true)
t << " -z:noxruns";
else
t << " -z:xruns";
if (csetup_repp->precise_sample_rates() == true)
t << " -z:psr";
else
t << " -z:nopsr";
if (csetup_repp->mix_mode() == ECA_CHAINSETUP::cs_mmode_avg)
t << " -z:mixmode,avg";
else
t << " -z:mixmode,sum";
t.setprecision(3);
if (csetup_repp->max_length_set()) {
t << " -t:" << csetup_repp->max_length_in_seconds_exact();
}
if (csetup_repp->looping_enabled()) t << " -tl";
return t.to_string();
}
string ECA_CHAINSETUP_PARSER::midi_to_string(void) const
{
MESSAGE_ITEM t;
t.setprecision(3);
std::vector<MIDI_IO*>::size_type p = 0;
while (p < csetup_repp->midi_devices.size()) {
t << "-Md:";
for(int n = 0; n < csetup_repp->midi_devices[p]->number_of_params(); n++) {
// FIXME: should quote/escape possible commas and whitespace
t << csetup_repp->midi_devices[p]->get_parameter(n + 1);
if (n + 1 < csetup_repp->midi_devices[p]->number_of_params()) t << ",";
}
++p;
if (p < csetup_repp->midi_devices.size()) t << " ";
}
return t.to_string();
}
string ECA_CHAINSETUP_PARSER::inputs_to_string(void) const
{
MESSAGE_ITEM t;
t.setprecision(3);
size_t p = 0;
while (p < csetup_repp->inputs.size()) {
t << "-a:";
std::vector<string> c = csetup_repp->get_attached_chains_to_input(csetup_repp->inputs[p]);
std::vector<string>::const_iterator cp = c.begin();
while (cp != c.end()) {
t << *cp;
++cp;
if (cp != c.end()) t << ",";
}
t << " "
<< ECA_OBJECT_FACTORY::audio_object_format_to_eos(csetup_repp->inputs[p])
<< " "
<< ECA_OBJECT_FACTORY::audio_object_to_eos(csetup_repp->inputs[p], "i");
if (csetup_repp->input_start_pos[p] != 0) {
t << " -y:" << csetup_repp->input_start_pos[p];
}
++p;
if (p < csetup_repp->inputs.size()) t << "\n";
}
return t.to_string();
}
string ECA_CHAINSETUP_PARSER::outputs_to_string(void) const
{
MESSAGE_ITEM t;
t.setprecision(3);
std::vector<AUDIO_IO*>::size_type p = 0;
while (p < csetup_repp->outputs.size()) {
t << "-a:";
std::vector<string> c = csetup_repp->get_attached_chains_to_output(csetup_repp->outputs[p]);
std::vector<string>::const_iterator cp = c.begin();
while (cp != c.end()) {
t << *cp;
++cp;
if (cp != c.end()) t << ",";
}
t << " "
<< ECA_OBJECT_FACTORY::audio_object_format_to_eos(csetup_repp->outputs[p])
<< " "
<< ECA_OBJECT_FACTORY::audio_object_to_eos(csetup_repp->outputs[p], "o");
if (csetup_repp->output_start_pos[p] != 0) {
t << " -y:" << csetup_repp->output_start_pos[p];
}
++p;
if (p < csetup_repp->outputs.size()) t << "\n";
}
return t.to_string();
}
string ECA_CHAINSETUP_PARSER::chains_to_string(void) const
{
MESSAGE_ITEM t;
std::vector<CHAIN*>::size_type p = 0;
while (p < csetup_repp->chains.size()) {
string tmpstr = csetup_repp->chains[p]->to_string();
if (tmpstr.size() > 0) {
t << "-a:" << csetup_repp->chains[p]->name() << " ";
t << tmpstr;
if (p + 1 < csetup_repp->chains.size()) t << "\n";
}
++p;
}
return t.to_string();
}