1
// ------------------------------------------------------------------------
2
// eca-session.cpp: Ecasound runtime setup and parameters.
3
// Copyright (C) 1999-2004 Kai Vehmanen
6
// eca-style-version: 3
8
// This program is fre software; you can redistribute it and/or modify
9
// it under the terms of the GNU General Public License as published by
10
// the Free Software Foundation; either version 2 of the License, or
11
// (at your option) any later version.
13
// This program is distributed in the hope that it will be useful,
14
// but WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
// GNU General Public License for more details.
18
// You should have received a copy of the GNU General Public License
19
// along with this program; if not, write to the Free Software
20
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
// ------------------------------------------------------------------------
33
#include <kvu_utils.h>
34
#include <kvu_com_line.h>
35
#include <kvu_message_item.h>
38
#include "eca-resources.h"
39
#include "eca-version.h"
41
#include "eca-chain.h"
44
#include "audioio-mp3.h"
45
#include "audioio-mikmod.h"
46
#include "audioio-timidity.h"
47
#include "audioio-ogg.h"
48
#include "audioio-flac.h"
49
#include "audioio-aac.h"
51
#include "osc-gen-file.h"
53
#include "eca-error.h"
54
#include "eca-logger.h"
55
#include "eca-logger.h"
56
#include "eca-session.h"
57
#include "eca-chainsetup.h"
62
ECA_SESSION::ECA_SESSION(void)
64
ECA_LOG_MSG(ECA_LOGGER::subsystems, "Session created (empty)");
68
ECA_SESSION::~ECA_SESSION(void)
70
// ECA_LOG_MSG(ECA_LOGGER::system_objects,"ECA_SESSION destructor!");
72
for(std::vector<ECA_CHAINSETUP*>::iterator q = chainsetups_rep.begin(); q != chainsetups_rep.end(); q++) {
77
ECA_SESSION::ECA_SESSION(COMMAND_LINE& cline) throw(ECA_ERROR&)
85
std::vector<std::string> options,csoptions;
86
create_chainsetup_options(cline, &options);
87
preprocess_options(&options);
88
errors += interpret_general_options(options,&csoptions);
90
/* NOTE: must be printed after general options are parsed
91
* in case user has specified -q (quiet operation) */
92
ECA_LOG_MSG(ECA_LOGGER::subsystems, "Session created");
95
throw(ECA_ERROR("ECA-SESSION", "Errors parsing session-level options. Unable to create session."));
98
if (chainsetups_rep.size() == 0) {
99
/* Try to create a valid chainsetup from the options given
100
* on the command-line. */
102
ECA_CHAINSETUP* comline_setup = new ECA_CHAINSETUP(csoptions);
104
if (comline_setup->interpret_result() != true) {
105
string temp = comline_setup->interpret_result_verbose();
106
delete comline_setup;
107
// std::cerr << "EXCEPTION DETECTED:'" << temp << "'. Core dump follows if you've compiled with gcc-3.3...\n";
108
throw(ECA_ERROR("ECA-SESSION", temp));
111
add_chainsetup(comline_setup); /* ownership object transfered */
112
if (selected_chainsetup_repp == 0) {
113
/* adding the chainsetup failed */
114
delete comline_setup;
116
else if (selected_chainsetup_repp->is_valid() != true) {
117
ECA_LOG_MSG(ECA_LOGGER::info, "Note! Unable to create a valid chainsetup from the command-line arguments.");
123
void ECA_SESSION::set_defaults(void)
125
connected_chainsetup_repp = 0;
126
selected_chainsetup_repp = 0;
129
// Interpret resources
131
ECA_RESOURCES ecaresources;
133
MP3FILE::set_input_cmd(ecaresources.resource("ext-cmd-mp3-input"));
134
MP3FILE::set_output_cmd(ecaresources.resource("ext-cmd-mp3-output"));
135
MIKMOD_INTERFACE::set_mikmod_cmd(ecaresources.resource("ext-cmd-mikmod"));
136
TIMIDITY_INTERFACE::set_timidity_cmd(ecaresources.resource("ext-cmd-timidity"));
137
OGG_VORBIS_INTERFACE::set_input_cmd(ecaresources.resource("ext-cmd-ogg-input"));
138
OGG_VORBIS_INTERFACE::set_output_cmd(ecaresources.resource("ext-cmd-ogg-output"));
139
FLAC_FORKED_INTERFACE::set_input_cmd(ecaresources.resource("ext-cmd-flac-input"));
140
FLAC_FORKED_INTERFACE::set_output_cmd(ecaresources.resource("ext-cmd-flac-output"));
141
AAC_FORKED_INTERFACE::set_input_cmd(ecaresources.resource("ext-cmd-aac-input"));
142
AAC_FORKED_INTERFACE::set_output_cmd(ecaresources.resource("ext-cmd-aac-output"));
147
* Add a new chainsetup
150
* name.empty() != true
153
* selected_chainsetup->name() == name ||
154
* chainsetup_names().size() has not changed
156
void ECA_SESSION::add_chainsetup(const std::string& name)
159
DBC_REQUIRE(name != "");
162
ECA_CHAINSETUP* newsetup = new ECA_CHAINSETUP;
163
newsetup->set_name(name);
164
add_chainsetup(newsetup);
165
if (selected_chainsetup_repp == 0) {
166
/* adding the chainsetup failed */
171
DBC_ENSURE(selected_chainsetup_repp != 0 &&
172
selected_chainsetup_repp->name() == name ||
173
selected_chainsetup_repp == 0);
178
* Add a new chainsetup. Ownership of the object given as argument
179
* is passed along the call. If a chainsetup with the same name already
180
* exists, the call will fail and the chainsetup given as argument
187
* (selected_chainsetup_repp == comline_setup &&
188
* static_cast<int>(chainsetups_rep.size()) == old_size + 1) ||
189
* (selected_chainsetup_repp == 0 &&
190
* static_cast<int>(chainsetups_rep.size()) == old_size)
192
void ECA_SESSION::add_chainsetup(ECA_CHAINSETUP* comline_setup)
195
DBC_REQUIRE(comline_setup != 0);
196
DBC_DECLARE(int old_size = chainsetups_rep.size());
199
selected_chainsetup_repp = comline_setup;
201
std::vector<ECA_CHAINSETUP*>::const_iterator p = chainsetups_rep.begin();
202
while(p != chainsetups_rep.end()) {
203
if ((*p)->name() == comline_setup->name()) {
204
ECA_LOG_MSG(ECA_LOGGER::info,
205
"Unable to add chainsetup, chainsetup with the same name already exists.");
206
selected_chainsetup_repp = 0;
212
if (selected_chainsetup_repp != 0) {
213
chainsetups_rep.push_back(selected_chainsetup_repp);
217
DBC_ENSURE((selected_chainsetup_repp == comline_setup &&
218
static_cast<int>(chainsetups_rep.size()) == old_size + 1) ||
219
(selected_chainsetup_repp == 0 &&
220
static_cast<int>(chainsetups_rep.size()) == old_size));
225
* Removes selected chainsetup
228
* connected_chainsetup != selected_chainsetup
231
* selected_chainsetup == 0
233
void ECA_SESSION::remove_chainsetup(void)
237
DBC_REQUIRE(connected_chainsetup_repp != selected_chainsetup_repp);
240
std::vector<ECA_CHAINSETUP*>::iterator p = chainsetups_rep.begin();
241
while(p != chainsetups_rep.end()) {
242
if (*p == selected_chainsetup_repp) {
243
selected_chainsetup_repp = 0;
245
chainsetups_rep.erase(p);
252
DBC_ENSURE(selected_chainsetup_repp == 0);
256
void ECA_SESSION::select_chainsetup(const std::string& name)
260
DBC_REQUIRE(name.empty() != true);
263
selected_chainsetup_repp = 0;
264
std::vector<ECA_CHAINSETUP*>::const_iterator p = chainsetups_rep.begin();
265
while(p != chainsetups_rep.end()) {
266
if ((*p)->name() == name) {
267
// ECA_LOG_MSG(ECA_LOGGER::system_objects, "Chainsetup \"" + name + "\" selected.");
268
selected_chainsetup_repp = *p;
275
DBC_ENSURE(selected_chainsetup_repp == 0 ||
276
selected_chainsetup_repp->name() == name);
280
void ECA_SESSION::save_chainsetup(void) throw(ECA_ERROR&)
284
DBC_REQUIRE(selected_chainsetup_repp != 0);
287
selected_chainsetup_repp->save();
290
void ECA_SESSION::save_chainsetup(const std::string& filename) throw(ECA_ERROR&)
294
DBC_REQUIRE(selected_chainsetup_repp != 0 && filename.empty() != true);
297
selected_chainsetup_repp->save_to_file(filename);
301
* Load a chainsetup from file (ecs). If operation fails,
302
* selected_chainsetup_repp == 0, ie. no chainsetup
305
* @post (selected_chainsetup_repp != 0 &&
306
* selected_chainsetup_repp->filename() == filename ||
307
* selected_chainsetup_repp == 0)
309
void ECA_SESSION::load_chainsetup(const std::string& filename)
312
DBC_REQUIRE(filename.empty() != true);
315
ECA_CHAINSETUP* new_setup = new ECA_CHAINSETUP(filename);
316
if (new_setup->interpret_result() != true) {
317
string temp = new_setup->interpret_result_verbose();
319
selected_chainsetup_repp = 0;
320
ECA_LOG_MSG(ECA_LOGGER::info, "Error loading chainsetup: " + temp);
323
add_chainsetup(new_setup);
324
if (selected_chainsetup_repp == 0) {
325
/* adding the chainsetup failed */
331
DBC_ENSURE(selected_chainsetup_repp != 0 &&
332
selected_chainsetup_repp->filename() == filename ||
333
selected_chainsetup_repp == 0);
337
void ECA_SESSION::connect_chainsetup(void) throw(ECA_ERROR&)
340
DBC_REQUIRE(selected_chainsetup_repp != 0);
341
DBC_REQUIRE(selected_chainsetup_repp->is_valid());
344
ECA_LOG_MSG(ECA_LOGGER::subsystems, "Connecting chainsetup");
346
if (selected_chainsetup_repp == connected_chainsetup_repp) return;
348
if (connected_chainsetup_repp != 0) {
349
disconnect_chainsetup();
353
* enable() throws an exception if it wasn't possibly
354
* to open/activate all input and output objects
356
selected_chainsetup_repp->enable();
357
connected_chainsetup_repp = selected_chainsetup_repp;
359
ECA_LOG_MSG(ECA_LOGGER::subsystems, "Chainsetup connected");
363
DBC_ENSURE(selected_chainsetup_repp == connected_chainsetup_repp);
367
void ECA_SESSION::disconnect_chainsetup(void)
370
DBC_REQUIRE(connected_chainsetup_repp != 0);
373
connected_chainsetup_repp->disable();
374
connected_chainsetup_repp = 0;
376
ECA_LOG_MSG(ECA_LOGGER::subsystems, "Chainsetup disconnected");
379
DBC_ENSURE(connected_chainsetup_repp == 0);
383
std::vector<std::string> ECA_SESSION::chainsetup_names(void) const
385
std::vector<std::string> result;
386
std::vector<ECA_CHAINSETUP*>::const_iterator p = chainsetups_rep.begin();
387
while(p != chainsetups_rep.end()) {
388
result.push_back((*p)->name());
394
void ECA_SESSION::create_chainsetup_options(COMMAND_LINE& cline,
395
std::vector<std::string>* options)
398
cline.next(); // skip the program name
399
while(cline.end() == false) {
400
options->push_back(cline.current());
406
* Tests whether the given argument is a session-level option.
408
bool ECA_SESSION::is_session_option(const std::string& arg) const
410
if (arg.size() < 2 ||
411
arg[0] != '-') return false;
419
if (arg.size() > 2 && arg[2] == ':') return true;
425
* Preprocesses a set of options.
427
* Notes! See also ECA_CHAINSETUP_PARSER::preprocess_options()
430
* all options valid for further processing (all options
431
* must start with a '-' sign)
433
void ECA_SESSION::preprocess_options(std::vector<std::string>* opts)
435
std::vector<std::string>::iterator p = opts->begin();
436
while(p != opts->end()) {
438
if (p->size() > 0 && (*p)[0] != '-') {
439
/* hack1: options ending with .ecs as "-s:file.ecs" */
440
string::size_type pos = p->find(".ecs");
441
if (pos + 4 == p->size()) {
442
ECA_LOG_MSG(ECA_LOGGER::info, "Note! Interpreting option " +
455
* Interprets all session specific options from 'inopts'.
456
* All unprocessed options are copied to 'outopts'.
458
* @return number of parsing errors
460
int ECA_SESSION::interpret_general_options(const std::vector<std::string>& inopts,
461
std::vector<std::string>* outopts)
465
std::vector<std::string>::const_iterator p = inopts.begin();
466
while(p != inopts.end()) {
467
if (p->size() > 0 && (*p)[0] == '-')
468
errors += interpret_general_option(*p);
473
while(p != inopts.end()) {
474
if (p->size() > 0 && (*p)[0] == '-')
475
errors += interpret_chainsetup_option(*p);
477
if (is_session_option(*p) != true) outopts->push_back(*p);
486
* Parses session option 'argu'.
488
* @return number of parsing errors
490
int ECA_SESSION::interpret_general_option (const std::string& argu)
492
if (argu.size() < 2) return 0;
493
if (argu[0] != '-') return 0;
498
if (argu.size() > 2 && argu[2] == ':') {
499
/* argu == "-d:XXX" */
500
ECA_LOGGER::instance().set_log_level_bitmask(atoi(kvu_get_argument_number(1, argu).c_str()));
503
/* argu == "-dXXX" */
505
ECA_LOGGER::instance().set_log_level_bitmask(0);
506
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::errors, 1);
507
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::info, 1);
508
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::subsystems, 1);
509
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::module_names, 1);
510
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::user_objects, 1);
511
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::eiam_return_values, 1);
513
if (argu.size() > 2 && argu[2] == 'd') {
515
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::system_objects, 1);
517
if (argu.size() > 3 && argu[3] == 'd') {
519
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::functions, 1);
520
ECA_LOGGER::instance().set_log_level(ECA_LOGGER::continuous, 1);
526
mtempd << "Set debug level to: " << ECA_LOGGER::instance().get_log_level_bitmask();
527
ECA_LOG_MSG(ECA_LOGGER::info, mtempd.to_string());
532
ECA_LOGGER::instance().disable();
542
* Parses session chainsetup option 'argu'.
544
* @return number of parsing errors
546
int ECA_SESSION::interpret_chainsetup_option (const std::string& argu)
550
if (argu.size() == 0) return errors;
552
string tname = kvu_get_argument_number(1, argu);
554
if (argu.size() < 2) return errors;
557
if (argu.size() > 2 && argu[2] == ':') {
558
load_chainsetup(tname);
559
if (selected_chainsetup_repp == 0 ||
560
selected_chainsetup_repp->is_valid_for_connection(true) != true) {
561
ECA_LOG_MSG(ECA_LOGGER::info, "Chainsetup loaded from '" + tname + "' is not valid!");
564
if (errors == 0) connect_chainsetup();