Logo Search packages:      
Sourcecode: ecasound version File versions  Download package

eca-chainsetup-parser.cpp

// ------------------------------------------------------------------------
// 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 successfully 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 successfully 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 successfully 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 successfully.");
  }
}

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
 */
00239 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();
}


Generated by  Doxygen 1.6.0   Back to index