~ubuntu-branches/ubuntu/wily/ecasound/wily-proposed

« back to all changes in this revision

Viewing changes to libecasound/eca-chainsetup.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghedini
  • Date: 2011-05-12 17:58:03 UTC
  • Revision ID: james.westby@ubuntu.com-20110512175803-zy3lodjecabt9r3v
Tags: upstream-2.8.0
ImportĀ upstreamĀ versionĀ 2.8.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// ------------------------------------------------------------------------
 
2
// eca-chainsetup.cpp: Class representing an ecasound chainsetup object.
 
3
// Copyright (C) 1999-2006,2008,2009,2011 Kai Vehmanen
 
4
// Copyright (C) 2005 Stuart Allie
 
5
//
 
6
// Attributes:
 
7
//     eca-style-version: 3 (see Ecasound Programmer's Guide)
 
8
//
 
9
// This program is free software; you can redistribute it and/or modify
 
10
// it under the terms of the GNU General Public License as published by
 
11
// the Free Software Foundation; either version 2 of the License, or
 
12
// (at your option) any later version.
 
13
// 
 
14
// This program is distributed in the hope that it will be useful,
 
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
17
// GNU General Public License for more details.
 
18
// 
 
19
// You should have received a copy of the GNU General Public License
 
20
// along with this program; if not, write to the Free Software
 
21
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 
22
// ------------------------------------------------------------------------
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include <config.h>
 
26
#endif
 
27
 
 
28
#include <string>
 
29
#include <cstring>
 
30
#include <algorithm>        /* find() */
 
31
#include <fstream>
 
32
#include <vector>
 
33
#include <list>
 
34
#include <iostream>
 
35
 
 
36
#include <sys/types.h>      /* POSIX: getpid() */
 
37
#include <unistd.h>         /* POSIX: getpid() */
 
38
#ifdef HAVE_SYS_MMAN_H
 
39
#include <sys/mman.h>       /* POSIX: for mlockall() */
 
40
#endif
 
41
 
 
42
#ifdef ECA_COMPILE_JACK
 
43
#include <jack/jack.h>
 
44
#endif
 
45
 
 
46
#include <kvu_dbc.h>
 
47
#include <kvu_message_item.h>
 
48
#include <kvu_numtostr.h>
 
49
#include <kvu_rtcaps.h>
 
50
#include <kvu_utils.h>
 
51
 
 
52
#include "eca-resources.h"
 
53
#include "eca-session.h"
 
54
 
 
55
#include "generic-controller.h"
 
56
#include "eca-chainop.h"
 
57
#include "eca-chain.h"
 
58
 
 
59
#include "audioio.h"
 
60
#include "audioio-manager.h"
 
61
#include "audioio-device.h"
 
62
#include "audioio-buffered.h"
 
63
#include "audioio-loop.h"
 
64
#include "audioio-null.h"
 
65
#include "audioio-resample.h"
 
66
 
 
67
#include "eca-engine-driver.h"
 
68
#include "eca-object-factory.h"
 
69
#include "eca-object-map.h"
 
70
 
 
71
#include "midiio.h"
 
72
#include "midi-client.h"
 
73
 
 
74
#include "eca-object-factory.h"
 
75
#include "eca-chainsetup-position.h"
 
76
#include "sample-specs.h"
 
77
 
 
78
#include "eca-error.h"
 
79
#include "eca-logger.h"
 
80
 
 
81
#include "eca-chainsetup.h"
 
82
#include "eca-chainsetup_impl.h"
 
83
 
 
84
using std::cerr;
 
85
using std::endl;
 
86
using namespace ECA;
 
87
 
 
88
const string ECA_CHAINSETUP::default_audio_format_const = "s16_le,2,44100,i";
 
89
const string ECA_CHAINSETUP::default_bmode_nonrt_const = "1024,false,50,false,100000,true";
 
90
const string ECA_CHAINSETUP::default_bmode_rt_const = "1024,true,50,true,100000,true";
 
91
const string ECA_CHAINSETUP::default_bmode_rtlowlatency_const = "256,true,50,true,100000,false";
 
92
 
 
93
static void priv_erase_object(std::vector<AUDIO_IO*>* vec, const AUDIO_IO* obj);
 
94
 
 
95
/**
 
96
 * Construct from a vector of options.
 
97
 * 
 
98
 * If any invalid options are passed us argument, 
 
99
 * interpret_result() will be 'false', and 
 
100
 * interpret_result_verbose() contains more detailed 
 
101
 * error description.
 
102
 */
 
103
ECA_CHAINSETUP::ECA_CHAINSETUP(const vector<string>& opts) 
 
104
  : cparser_rep(this),
 
105
    is_enabled_rep(false)
 
106
{
 
107
  impl_repp = new ECA_CHAINSETUP_impl;
 
108
 
 
109
  // FIXME: set default audio format here!
 
110
 
 
111
  setup_name_rep = "untitled-chainsetup";
 
112
  setup_filename_rep = "";
 
113
 
 
114
  set_defaults();
 
115
 
 
116
  vector<string> options (opts);
 
117
  cparser_rep.preprocess_options(options);
 
118
  interpret_options(options);
 
119
  if (interpret_result() == true) {
 
120
    /* do not add default if there were parsing errors as
 
121
     * it might hide real problems */
 
122
    add_default_output();
 
123
    add_default_midi_device();
 
124
  }
 
125
 
 
126
  ECA_LOG_MSG(ECA_LOGGER::info, "Chainsetup \"" + setup_name_rep + "\"");
 
127
}
 
128
 
 
129
/**
 
130
 * Constructs an empty chainsetup.
 
131
 *
 
132
 * @post buffersize != 0
 
133
 */
 
134
ECA_CHAINSETUP::ECA_CHAINSETUP(void) 
 
135
  : cparser_rep(this),
 
136
    is_enabled_rep(false)
 
137
{
 
138
  impl_repp = new ECA_CHAINSETUP_impl;
 
139
 
 
140
  setup_name_rep = "";
 
141
  set_defaults();
 
142
 
 
143
  ECA_LOG_MSG(ECA_LOGGER::info, "Chainsetup created (empty)");
 
144
}
 
145
 
 
146
/**
 
147
 * Construct from a chainsetup file.
 
148
 * 
 
149
 * If any invalid options are passed us argument, 
 
150
 * interpret_result() will be 'false', and 
 
151
 * interpret_result_verbose() contains more detailed 
 
152
 * error description.
 
153
 *
 
154
 * @post buffersize != 0
 
155
 */
 
156
ECA_CHAINSETUP::ECA_CHAINSETUP(const string& setup_file) 
 
157
  : cparser_rep(this),
 
158
    is_enabled_rep(false)
 
159
{
 
160
  impl_repp = new ECA_CHAINSETUP_impl;
 
161
 
 
162
  setup_name_rep = "";
 
163
  set_defaults();
 
164
  vector<string> options;
 
165
  load_from_file(setup_file, options);
 
166
  set_filename(setup_file);
 
167
  if (name() == "") set_name(setup_file);
 
168
  cparser_rep.preprocess_options(options);
 
169
  interpret_options(options);
 
170
  if (interpret_result() == true) {
 
171
    /* do not add default if there were parsing errors as
 
172
     * it might hide real problems */
 
173
    add_default_output();
 
174
  }
 
175
 
 
176
  ECA_LOG_MSG(ECA_LOGGER::info, 
 
177
              "Chainsetup \"" 
 
178
              + name() + "\" created (file: "
 
179
              + setup_file + ")"); 
 
180
}
 
181
 
 
182
/**
 
183
 * Destructor
 
184
 */
 
185
ECA_CHAINSETUP::~ECA_CHAINSETUP(void)
 
186
 
187
  ECA_LOG_MSG(ECA_LOGGER::system_objects,"ECA_CHAINSETUP destructor-in");
 
188
 
 
189
  DBC_CHECK(is_locked() != true);
 
190
  if (is_enabled() == true) {
 
191
    disable();
 
192
  }
 
193
  DBC_CHECK(is_enabled() != true);
 
194
 
 
195
  /* delete chain objects */
 
196
  for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
197
    ECA_LOG_MSG(ECA_LOGGER::user_objects, "Deleting chain \"" + (*q)->name() + "\".");
 
198
    delete *q;
 
199
    *q = 0;
 
200
  }
 
201
 
 
202
  /* delete input db objects; reset all pointers to null */
 
203
  for(vector<AUDIO_IO*>::iterator q = inputs.begin(); q != inputs.end(); q++) {
 
204
    if (dynamic_cast<AUDIO_IO_DB_CLIENT*>(*q) != 0) {
 
205
      ECA_LOG_MSG(ECA_LOGGER::user_objects, "Deleting audio db-client \"" + (*q)->label() + "\".");
 
206
      delete *q;
 
207
    }
 
208
    *q = 0;
 
209
  }
 
210
 
 
211
  /* delete all actual audio input objects except loop devices; reset all pointers to null */
 
212
  for(vector<AUDIO_IO*>::iterator q = inputs_direct_rep.begin(); q != inputs_direct_rep.end(); q++) {
 
213
    if (dynamic_cast<LOOP_DEVICE*>(*q) == 0) { 
 
214
      ECA_LOG_MSG(ECA_LOGGER::user_objects, "Deleting audio object \"" + (*q)->label() + "\".");
 
215
      delete *q;
 
216
    }
 
217
    *q = 0;
 
218
  }
 
219
 
 
220
  /* delete output db objects; reset all pointers to null */
 
221
  for(vector<AUDIO_IO*>::iterator q = outputs.begin(); q != outputs.end(); q++) {
 
222
    if (dynamic_cast<AUDIO_IO_DB_CLIENT*>(*q) != 0) {
 
223
      ECA_LOG_MSG(ECA_LOGGER::user_objects, "Deleting audio db-client \"" + (*q)->label() + "\".");
 
224
      delete *q;
 
225
    }
 
226
    *q = 0;
 
227
  }
 
228
 
 
229
  /* delete all actual audio output objects except loop devices; reset all pointers to null */
 
230
  for(vector<AUDIO_IO*>::iterator q = outputs_direct_rep.begin(); q != outputs_direct_rep.end(); q++) {
 
231
    // trouble with dynamic_cast with libecasoundc apps like ecalength?
 
232
    if (dynamic_cast<LOOP_DEVICE*>(*q) == 0) { 
 
233
      ECA_LOG_MSG(ECA_LOGGER::user_objects, "Deleting audio object \"" + (*q)->label() + "\".");
 
234
      delete *q;
 
235
      *q = 0;
 
236
    }
 
237
  }
 
238
 
 
239
  /* delete loop objects */
 
240
  for(map<string,LOOP_DEVICE*>::iterator q = loop_map.begin(); q != loop_map.end(); q++) {
 
241
    ECA_LOG_MSG(ECA_LOGGER::user_objects, "Deleting loop device \"" + q->second->label() + "\".");
 
242
    delete q->second;
 
243
    q->second = 0;
 
244
  }
 
245
 
 
246
  /* delete aio manager objects */
 
247
  for(vector<AUDIO_IO_MANAGER*>::iterator q = aio_managers_rep.begin(); q != aio_managers_rep.end(); q++) {
 
248
    ECA_LOG_MSG(ECA_LOGGER::user_objects, "Deleting audio manager \"" + (*q)->name() + "\".");
 
249
    delete *q;
 
250
    *q = 0;
 
251
  }
 
252
 
 
253
  delete impl_repp;
 
254
 
 
255
  ECA_LOG_MSG(ECA_LOGGER::system_objects,"ECA_CHAINSETUP destructor-out");
 
256
}
 
257
 
 
258
/**
 
259
 * Sets default values.
 
260
 *
 
261
 * @pre is_enabled() != true
 
262
 */
 
263
void ECA_CHAINSETUP::set_defaults(void)
 
264
{
 
265
  // --------
 
266
  DBC_REQUIRE(is_enabled() != true);
 
267
  // --------
 
268
 
 
269
  /* note: defaults are set as specified in ecasoundrc(5) */
 
270
 
 
271
  precise_sample_rates_rep = false;
 
272
  ignore_xruns_rep = true;
 
273
 
 
274
  pserver_repp = &impl_repp->pserver_rep;
 
275
  midi_server_repp = &impl_repp->midi_server_rep;
 
276
  engine_driver_repp = 0;
 
277
 
 
278
  if (kvu_check_for_sched_fifo() == true) {
 
279
    rtcaps_rep = true;
 
280
    ECA_LOG_MSG(ECA_LOGGER::system_objects, "Rtcaps detected.");
 
281
  }
 
282
  else 
 
283
    rtcaps_rep = false;
 
284
 
 
285
  db_clients_rep = 0;
 
286
  multitrack_mode_rep = false;
 
287
  multitrack_mode_override_rep = false;
 
288
  memory_locked_rep = false;
 
289
  midi_server_needed_rep = false;
 
290
  is_locked_rep = false;
 
291
  selected_chain_index_rep = 0;
 
292
  selected_ctrl_index_rep = 0;
 
293
  selected_ctrl_param_index_rep = 0;
 
294
  multitrack_mode_offset_rep = -1;
 
295
 
 
296
  buffering_mode_rep = cs_bmode_auto;
 
297
  active_buffering_mode_rep = cs_bmode_none;
 
298
 
 
299
  set_output_openmode(AUDIO_IO::io_readwrite);
 
300
 
 
301
  ECA_RESOURCES ecaresources;
 
302
  if (ecaresources.has_any() != true) {
 
303
    ECA_LOG_MSG(ECA_LOGGER::info, 
 
304
                "WARNING: Unable to read global resources. May result in incorrect behaviour.");
 
305
  }
 
306
  
 
307
  set_default_midi_device(ecaresources.resource("midi-device"));
 
308
  string rc_temp = set_resource_helper(ecaresources,
 
309
                                       "default-audio-format", 
 
310
                                       ECA_CHAINSETUP::default_audio_format_const);
 
311
  cparser_rep.interpret_object_option("-f:" + rc_temp);
 
312
  set_samples_per_second(default_audio_format().samples_per_second());
 
313
  toggle_precise_sample_rates(ecaresources.boolean_resource("default-to-precise-sample-rates"));
 
314
  rc_temp = set_resource_helper(ecaresources, 
 
315
                                "default-mix-mode", 
 
316
                                "avg");
 
317
  cparser_rep.interpret_object_option("-z:mixmode," + rc_temp);
 
318
 
 
319
  impl_repp->bmode_nonrt_rep.set_all(set_resource_helper(ecaresources,
 
320
                                                         "bmode-defaults-nonrt",
 
321
                                                         ECA_CHAINSETUP::default_bmode_nonrt_const));
 
322
  impl_repp->bmode_rt_rep.set_all(set_resource_helper(ecaresources,
 
323
                                                      "bmode-defaults-rt",
 
324
                                                      ECA_CHAINSETUP::default_bmode_rt_const));
 
325
  impl_repp->bmode_rtlowlatency_rep.set_all(set_resource_helper(ecaresources,
 
326
                                                                "bmode-defaults-rtlowlatency",
 
327
                                                                ECA_CHAINSETUP::default_bmode_rtlowlatency_const));
 
328
 
 
329
  impl_repp->bmode_active_rep = impl_repp->bmode_nonrt_rep;
 
330
}
 
331
 
 
332
/**
 
333
 * Sets a resource value.
 
334
 *
 
335
 * Only used by ECA_CHAINSETUP::set_defaults.
 
336
 */
 
337
string ECA_CHAINSETUP::set_resource_helper(const ECA_RESOURCES& ecaresources, const string& tag, const string& alternative)
 
338
{
 
339
  if (ecaresources.has(tag) == true) {
 
340
    return ecaresources.resource(tag);
 
341
  }
 
342
  else {
 
343
    ECA_LOG_MSG(ECA_LOGGER::system_objects,
 
344
                "Using hardcoded defaults for \"" +
 
345
                tag + "\".");
 
346
    return alternative;
 
347
  }
 
348
}
 
349
 
 
350
/**
 
351
 * Tests whether chainsetup is in a valid state.
 
352
 */
 
353
bool ECA_CHAINSETUP::is_valid(void) const
 
354
{
 
355
  return is_valid_for_connection(false);
 
356
}
 
357
 
 
358
/**
 
359
 * Checks whether chainsetup is valid for enabling/connecting. 
 
360
 * If chainsetup is not valid and 'verbose' is true, detected
 
361
 * errors are reported via the logging subsystem.
 
362
 */
 
363
bool ECA_CHAINSETUP::is_valid_for_connection(bool verbose) const 
 
364
{
 
365
  bool result = true;
 
366
 
 
367
  if (inputs.size() == 0) {
 
368
    if (verbose) ECA_LOG_MSG(ECA_LOGGER::info, 
 
369
                             "Unable to connect: No inputs in the current chainsetup. (1.1-NO-INPUTS)");
 
370
    result = false;
 
371
  }
 
372
  else if (outputs.size() == 0) {
 
373
    if (verbose) ECA_LOG_MSG(ECA_LOGGER::info, 
 
374
                             "Unable to connect: No outputs in the current chainsetup. (1.2-NO-OUTPUTS)");
 
375
    result = false;
 
376
  }
 
377
  else if (chains.size() == 0) {
 
378
    if (verbose) ECA_LOG_MSG(ECA_LOGGER::info, 
 
379
                             "Unable to connect: No chains in the current chainsetup. (1.3-NO-CHAINS)");
 
380
    result = false;
 
381
  }
 
382
  else {
 
383
    list<int> conn_inputs, conn_outputs;
 
384
 
 
385
    for(vector<CHAIN*>::const_iterator q = chains.begin(); q != chains.end(); q++) {
 
386
      /* log messages printed in CHAIN::is_valid() */
 
387
 
 
388
      int id = (*q)->connected_input();
 
389
      if (id > -1) 
 
390
        conn_inputs.push_back(id);
 
391
      
 
392
      if ((*q)->is_valid() == false) {
 
393
        result = false;
 
394
        if (verbose) ECA_LOG_MSG(ECA_LOGGER::info, 
 
395
                                 "Unable to connect: Chain \"" + (*q)->name() + 
 
396
                                 "\" is not valid. Following errors were detected:");
 
397
        if (verbose && id == -1) {
 
398
          ECA_LOG_MSG(ECA_LOGGER::info, 
 
399
                      "Chain \"" + (*q)->name() + "\" is not connected to any input. "
 
400
                      "All chains must have exactly one valid input. (2.1-NO-CHAIN-INPUT)");
 
401
        }
 
402
      }
 
403
 
 
404
      id = (*q)->connected_output();
 
405
      if (id > -1) 
 
406
        conn_outputs.push_back(id);
 
407
 
 
408
      if (verbose && (*q)->is_valid() == false) {
 
409
        if (id == -1) {
 
410
          ECA_LOG_MSG(ECA_LOGGER::info, 
 
411
                      "Chain \"" + (*q)->name() + "\" is not connected to any output. "
 
412
                      "All chains must have exactly one valid output. (2.2-NO-CHAIN-OUTPUT)");
 
413
        }
 
414
      }
 
415
    }
 
416
 
 
417
    // FIXME: doesn't work yet
 
418
 
 
419
    if (verbose) {
 
420
      for(int n = 0; n < static_cast<int>(inputs.size()); n++) {
 
421
        if (std::find(conn_inputs.begin(), conn_inputs.end(), n) == conn_inputs.end()) {
 
422
          ECA_LOG_MSG(ECA_LOGGER::info, 
 
423
                      "WARNING: Input \"" + inputs[n]->label() + "\" is not connected to any chain. (3.1-DISCON-INPUT)");
 
424
        }
 
425
      }
 
426
      
 
427
      for(int n = 0; n < static_cast<int>(outputs.size()); n++) {
 
428
        if (std::find(conn_outputs.begin(), conn_outputs.end(), n) == conn_outputs.end()) {
 
429
          ECA_LOG_MSG(ECA_LOGGER::info, 
 
430
                      "WARNING: Output \"" + outputs[n]->label() + "\" is not connected to any chain. (3.2-DISCON-OUTPUT)");
 
431
        }
 
432
      }
 
433
    }
 
434
  } /* (verbose == true) */
 
435
 
 
436
  return result;
 
437
}
 
438
 
 
439
void ECA_CHAINSETUP::set_buffering_mode(Buffering_mode_t value)
 
440
{
 
441
  if (value == ECA_CHAINSETUP::cs_bmode_none)
 
442
    buffering_mode_rep = ECA_CHAINSETUP::cs_bmode_auto;
 
443
  else
 
444
    buffering_mode_rep = value;
 
445
}
 
446
 
 
447
/**
 
448
 * Sets audio i/o manager option for manager
 
449
 * object type 'mgrname' to be 'optionstr'.
 
450
 * Previously set option string is overwritten.
 
451
 */
 
452
void ECA_CHAINSETUP::set_audio_io_manager_option(const string& mgrname, const string& optionstr)
 
453
{
 
454
  ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
455
              "Set manager \"" +
 
456
              mgrname + "\" option string to \"" +
 
457
              optionstr + "\".");
 
458
 
 
459
  aio_manager_option_map_rep[mgrname] = optionstr;
 
460
  propagate_audio_io_manager_options();
 
461
}
 
462
 
 
463
/**
 
464
 * Determinates the active buffering parameters based on
 
465
 * defaults, user overrides and analyzing the current 
 
466
 * chainsetup configuration. If the resulting parameters 
 
467
 * are different from current ones, a state change is
 
468
 * performed.
 
469
 */ 
 
470
void ECA_CHAINSETUP::select_active_buffering_mode(void)
 
471
{
 
472
  if (buffering_mode() == ECA_CHAINSETUP::cs_bmode_none) {
 
473
    active_buffering_mode_rep = ECA_CHAINSETUP::cs_bmode_auto;
 
474
  }
 
475
  
 
476
  if (!(multitrack_mode_override_rep == true && 
 
477
        multitrack_mode_rep != true) && 
 
478
      ((multitrack_mode_override_rep == true && 
 
479
        multitrack_mode_rep == true) ||
 
480
       (number_of_realtime_inputs() > 0 && 
 
481
        number_of_realtime_outputs() > 0 &&
 
482
        number_of_non_realtime_inputs() > 0 && 
 
483
        number_of_non_realtime_outputs() > 0 &&
 
484
        chains.size() > 1))) {
 
485
    ECA_LOG_MSG(ECA_LOGGER::info, "Multitrack-mode enabled.");
 
486
    multitrack_mode_rep = true;
 
487
  }
 
488
  else
 
489
    multitrack_mode_rep = false;
 
490
  
 
491
  if (buffering_mode() == ECA_CHAINSETUP::cs_bmode_auto) {
 
492
 
 
493
    /* initialize to 'nonrt', mt-disabled */
 
494
    active_buffering_mode_rep = ECA_CHAINSETUP::cs_bmode_nonrt;
 
495
 
 
496
    if (has_realtime_objects() == true) {
 
497
      /* case 1: a multitrack setup */
 
498
      if (multitrack_mode_rep == true) {
 
499
        active_buffering_mode_rep = ECA_CHAINSETUP::cs_bmode_rt;
 
500
        ECA_LOG_MSG(ECA_LOGGER::system_objects, "bmode-selection case-1");
 
501
      }
 
502
 
 
503
      /* case 2: rt-objects without priviledges for rt-scheduling */
 
504
      else if (rtcaps_rep != true) {
 
505
        ECA_LOG_MSG(ECA_LOGGER::info,
 
506
                    "NOTE: Real-time configuration, but insufficient privileges to utilize real-time scheduling (SCHED_FIFO). With small buffersizes, this may cause audible glitches during processing.");
 
507
        toggle_raised_priority(false);
 
508
        active_buffering_mode_rep = ECA_CHAINSETUP::cs_bmode_rt;
 
509
        ECA_LOG_MSG(ECA_LOGGER::system_objects, "bmode-selection case-2");
 
510
      }
 
511
 
 
512
      /* case 3: no chain operators and "one-way rt-operation" */
 
513
      else if (number_of_chain_operators() == 0 &&
 
514
               (number_of_realtime_inputs() == 0 || 
 
515
                number_of_realtime_outputs() == 0)) {
 
516
        active_buffering_mode_rep = ECA_CHAINSETUP::cs_bmode_rt;
 
517
        ECA_LOG_MSG(ECA_LOGGER::system_objects, "bmode-selection case-3");
 
518
      }
 
519
 
 
520
      /* case 4: default for rt-setups */
 
521
      else {
 
522
        active_buffering_mode_rep = ECA_CHAINSETUP::cs_bmode_rtlowlatency;
 
523
        ECA_LOG_MSG(ECA_LOGGER::system_objects, "bmode-selection case-4");
 
524
      }
 
525
    }
 
526
    else { 
 
527
      /* case 5: no rt-objects */
 
528
      active_buffering_mode_rep = ECA_CHAINSETUP::cs_bmode_nonrt;
 
529
      ECA_LOG_MSG(ECA_LOGGER::system_objects, "bmode-selection case-5");
 
530
    }
 
531
  }
 
532
  else {
 
533
    /* user has explicitly selected the buffering mode */
 
534
    active_buffering_mode_rep = buffering_mode();
 
535
    ECA_LOG_MSG(ECA_LOGGER::system_objects, "bmode-selection explicit");
 
536
  }
 
537
  
 
538
  switch(active_buffering_mode_rep) 
 
539
    {
 
540
    case ECA_CHAINSETUP::cs_bmode_nonrt: { 
 
541
      impl_repp->bmode_active_rep = impl_repp->bmode_nonrt_rep;
 
542
      ECA_LOG_MSG(ECA_LOGGER::info, 
 
543
                    "\"nonrt\" buffering mode selected.");
 
544
      break; 
 
545
    }
 
546
    case ECA_CHAINSETUP::cs_bmode_rt: { 
 
547
      impl_repp->bmode_active_rep = impl_repp->bmode_rt_rep;
 
548
      ECA_LOG_MSG(ECA_LOGGER::info, 
 
549
                    "\"rt\" buffering mode selected.");
 
550
      break; 
 
551
    }
 
552
    case ECA_CHAINSETUP::cs_bmode_rtlowlatency: { 
 
553
      impl_repp->bmode_active_rep = impl_repp->bmode_rtlowlatency_rep;
 
554
      ECA_LOG_MSG(ECA_LOGGER::info, 
 
555
                    "\"rtlowlatency\" buffering mode selected.");
 
556
      break;
 
557
    }
 
558
    default: { /* error! */ }
 
559
    }
 
560
 
 
561
  ECA_LOG_MSG(ECA_LOGGER::system_objects,
 
562
                "Set buffering parameters to: \n--cut--" +
 
563
                impl_repp->bmode_active_rep.to_string() +"\n--cut--");
 
564
}
 
565
 
 
566
/**
 
567
 * Enable chosen active buffering mode.
 
568
 * 
 
569
 * Called only from enable().
 
570
 */
 
571
void ECA_CHAINSETUP::enable_active_buffering_mode(void)
 
572
{
 
573
  /* 1. if requested, lock all memory */
 
574
  if (raised_priority() == true) {
 
575
    lock_all_memory();
 
576
  }
 
577
  else {
 
578
    unlock_all_memory();
 
579
  }
 
580
 
 
581
  /* 2. if necessary, switch between different db and direct modes */
 
582
  if (double_buffering() == true) {
 
583
    if (has_realtime_objects() != true) {
 
584
      ECA_LOG_MSG(ECA_LOGGER::system_objects,
 
585
                    "No realtime objects; switching to direct mode.");
 
586
      switch_to_direct_mode();
 
587
      impl_repp->bmode_active_rep.toggle_double_buffering(false);
 
588
    }
 
589
    else if (has_nonrealtime_objects() != true) {
 
590
      ECA_LOG_MSG(ECA_LOGGER::system_objects,
 
591
                    "Only realtime objects; switching to direct mode.");
 
592
      switch_to_direct_mode();
 
593
      impl_repp->bmode_active_rep.toggle_double_buffering(false);
 
594
    }
 
595
    else if (db_clients_rep == 0) {
 
596
      ECA_LOG_MSG(ECA_LOGGER::system_objects,
 
597
                    "Switching to db mode.");
 
598
      switch_to_db_mode();
 
599
    }
 
600
 
 
601
    if (buffersize() != 0) {
 
602
      impl_repp->pserver_rep.set_buffer_defaults(double_buffer_size() / buffersize(), 
 
603
                                                 buffersize());
 
604
    }
 
605
    else {
 
606
      ECA_LOG_MSG(ECA_LOGGER::info,
 
607
                    "WARNING: Buffersize set to 0.");
 
608
      impl_repp->pserver_rep.set_buffer_defaults(0, 0);
 
609
    }
 
610
  }
 
611
  else {
 
612
    /* double_buffering() != true */
 
613
    if (db_clients_rep > 0) {
 
614
      ECA_LOG_MSG(ECA_LOGGER::system_objects,
 
615
                    "Switching to direct mode.");
 
616
      switch_to_direct_mode();
 
617
    }
 
618
  }
 
619
 
 
620
  /* 3. propagate buffersize value to all dependent objects */
 
621
  /* FIXME: create a system for tracking buffesize aware objs */
 
622
}
 
623
 
 
624
void ECA_CHAINSETUP::switch_to_direct_mode(void)
 
625
{
 
626
  switch_to_direct_mode_helper(&inputs, inputs_direct_rep);
 
627
  switch_to_direct_mode_helper(&outputs, outputs_direct_rep);
 
628
  // --
 
629
  DBC_ENSURE(db_clients_rep == 0);
 
630
  // --
 
631
}
 
632
 
 
633
void ECA_CHAINSETUP::switch_to_direct_mode_helper(vector<AUDIO_IO*>* objs, 
 
634
                                                  const vector<AUDIO_IO*>& directobjs)
 
635
{
 
636
  // --
 
637
  DBC_CHECK(objs->size() == directobjs.size());
 
638
  // --
 
639
 
 
640
  for(size_t n = 0; n < objs->size(); n++) {
 
641
    AUDIO_IO_DB_CLIENT* pobj = dynamic_cast<AUDIO_IO_DB_CLIENT*>((*objs)[n]);
 
642
    if (pobj != 0) {
 
643
      delete (*objs)[n];
 
644
      (*objs)[n] = directobjs[n];
 
645
      --db_clients_rep;
 
646
    }
 
647
  } 
 
648
}
 
649
 
 
650
void ECA_CHAINSETUP::switch_to_db_mode(void)
 
651
{
 
652
  switch_to_db_mode_helper(&inputs, inputs_direct_rep);
 
653
  switch_to_db_mode_helper(&outputs, outputs_direct_rep);
 
654
}
 
655
 
 
656
void ECA_CHAINSETUP::switch_to_db_mode_helper(vector<AUDIO_IO*>* objs, 
 
657
                                                 const vector<AUDIO_IO*>& directobjs)
 
658
{
 
659
  // --
 
660
  DBC_REQUIRE(db_clients_rep == 0);
 
661
  DBC_CHECK(objs->size() == directobjs.size());
 
662
  // --
 
663
 
 
664
  for(size_t n = 0; n < directobjs.size(); n++) {
 
665
    (*objs)[n] = add_audio_object_helper(directobjs[n]);
 
666
  } 
 
667
}
 
668
 
 
669
/**
 
670
 * Locks all memory with mlockall().
 
671
 */
 
672
void ECA_CHAINSETUP::lock_all_memory(void)
 
673
{
 
674
#ifdef HAVE_MLOCKALL
 
675
  if (::mlockall (MCL_CURRENT|MCL_FUTURE)) {
 
676
    ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: Couldn't lock all memory!");
 
677
  }
 
678
  else {
 
679
    ECA_LOG_MSG(ECA_LOGGER::system_objects, "Memory locked!");
 
680
    memory_locked_rep = true;
 
681
  }
 
682
#else
 
683
  ECA_LOG_MSG(ECA_LOGGER::info, "Memory locking not available.");
 
684
#endif
 
685
}
 
686
 
 
687
/**
 
688
 * Unlocks all memory with munlockall().
 
689
 */
 
690
void ECA_CHAINSETUP::unlock_all_memory(void)
 
691
{
 
692
#ifdef HAVE_MUNLOCKALL
 
693
  if (memory_locked_rep == true) {
 
694
    if (::munlockall()) {
 
695
      ECA_LOG_MSG(ECA_LOGGER::system_objects, "WARNING: Couldn't unlock all memory!");
 
696
    }
 
697
    else 
 
698
      ECA_LOG_MSG(ECA_LOGGER::system_objects, "Memory unlocked!");
 
699
    memory_locked_rep = false;
 
700
  }
 
701
#else
 
702
  memory_locked_rep = false;
 
703
  ECA_LOG_MSG(ECA_LOGGER::system_objects, "Memory unlocking not available.");
 
704
#endif
 
705
}
 
706
 
 
707
/**
 
708
 * Adds a "default" chain to this chainsetup.
 
709
 *
 
710
 * @pre buffersize >= 0 && chains.size() == 0
 
711
 * @pre is_locked() != true
 
712
 *
 
713
 * @post chains.back()->name() == "default" && 
 
714
 * @post active_chainids.back() == "default"
 
715
 */
 
716
void ECA_CHAINSETUP::add_default_chain(void)
 
717
{
 
718
  // --------
 
719
  DBC_REQUIRE(buffersize() >= 0);
 
720
  DBC_REQUIRE(chains.size() == 0);
 
721
  DBC_REQUIRE(is_locked() != true);
 
722
  // --------
 
723
 
 
724
  add_chain_helper("default");
 
725
  selected_chainids.push_back("default");
 
726
 
 
727
  // --------
 
728
  DBC_ENSURE(chains.back()->name() == "default");
 
729
  DBC_ENSURE(selected_chainids.back() == "default");
 
730
  // --------  
 
731
}
 
732
 
 
733
/**
 
734
 * Adds new chains to this chainsetup.
 
735
 * 
 
736
 * @pre is_enabled() != true
 
737
 */
 
738
void ECA_CHAINSETUP::add_new_chains(const vector<string>& newchains)
 
739
{
 
740
  // --------
 
741
  DBC_REQUIRE(is_enabled() != true);
 
742
  // --------
 
743
 
 
744
  for(vector<string>::const_iterator p = newchains.begin(); p != newchains.end(); p++) {
 
745
    bool exists = false;
 
746
    for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
747
      if (*p == (*q)->name()) exists = true;
 
748
    }
 
749
    if (exists == false) {
 
750
      add_chain_helper(*p);
 
751
    }
 
752
  }
 
753
}
 
754
 
 
755
void ECA_CHAINSETUP::add_chain_helper(const string& name)
 
756
{
 
757
  chains.push_back(new CHAIN());
 
758
  chains.back()->name(name);
 
759
  chains.back()->set_samples_per_second(samples_per_second());
 
760
  ECA_LOG_MSG(ECA_LOGGER::user_objects, "Chain \"" + name + "\" created.");
 
761
}
 
762
 
 
763
/**
 
764
 * Removes all selected chains from this chainsetup.
 
765
 *
 
766
 * @pre is_enabled() != true
 
767
 */
 
768
void ECA_CHAINSETUP::remove_chains(void)
 
769
{
 
770
  // --------
 
771
  DBC_REQUIRE(is_enabled() != true);
 
772
  DBC_DECLARE(size_t old_chains_size = chains.size());
 
773
  DBC_DECLARE(size_t sel_chains_size = selected_chainids.size());
 
774
  // --------
 
775
 
 
776
  for(vector<string>::const_iterator a = selected_chainids.begin(); a != selected_chainids.end(); a++) {
 
777
    vector<CHAIN*>::iterator q = chains.begin();
 
778
    while(q != chains.end()) {
 
779
      if (*a == (*q)->name()) {
 
780
        delete *q;
 
781
        chains.erase(q);
 
782
        break;
 
783
      }
 
784
      ++q;
 
785
    }
 
786
  }
 
787
  selected_chainids.resize(0);
 
788
 
 
789
  // --
 
790
  DBC_ENSURE(chains.size() == old_chains_size - sel_chains_size);
 
791
  // --
 
792
}
 
793
 
 
794
/**
 
795
 * Clears all selected chains. Removes all chain operators
 
796
 * and controllers.
 
797
 *
 
798
 * @pre is_locked() != true
 
799
 */
 
800
void ECA_CHAINSETUP::clear_chains(void)
 
801
{
 
802
  // --------
 
803
  DBC_REQUIRE(is_locked() != true);
 
804
  // --------
 
805
 
 
806
  for(vector<string>::const_iterator a = selected_chainids.begin(); a != selected_chainids.end(); a++) {
 
807
    for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
808
      if (*a == (*q)->name()) {
 
809
        (*q)->clear();
 
810
      }
 
811
    }
 
812
  }
 
813
}
 
814
 
 
815
/**
 
816
 * Renames the first selected chain.
 
817
 */
 
818
void ECA_CHAINSETUP::rename_chain(const string& name)
 
819
{
 
820
  for(vector<string>::const_iterator a = selected_chainids.begin(); a != selected_chainids.end(); a++) {
 
821
    for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
822
      if (*a == (*q)->name()) {
 
823
        (*q)->name(name);
 
824
        return;
 
825
      }
 
826
    }
 
827
  }
 
828
}
 
829
 
 
830
/**
 
831
 * Selects all chains present in this chainsetup.
 
832
 */
 
833
void ECA_CHAINSETUP::select_all_chains(void)
 
834
{
 
835
  vector<CHAIN*>::const_iterator p = chains.begin();
 
836
  selected_chainids.resize(0);
 
837
  while(p != chains.end()) {
 
838
    selected_chainids.push_back((*p)->name());
 
839
    ++p;
 
840
  }
 
841
}
 
842
 
 
843
/**
 
844
 * Returns the index number of first selected chains. If no chains 
 
845
 * are selected, returns 'last_index + 1' (==chains.size()).
 
846
 */
 
847
unsigned int ECA_CHAINSETUP::first_selected_chain(void) const
 
848
{
 
849
  const vector<string>& schains = selected_chains();
 
850
  vector<string>::const_iterator o = schains.begin();
 
851
  unsigned int p = chains.size();
 
852
  while(o != schains.end()) {
 
853
    for(p = 0; p != chains.size(); p++) {
 
854
      if (chains[p]->name() == *o)
 
855
        return p;
 
856
    }
 
857
    ++o;
 
858
  }
 
859
  return p;
 
860
}
 
861
 
 
862
/**
 
863
 * Toggles chain muting of all selected chains.
 
864
 *
 
865
 * @pre is_locked() != true
 
866
 */
 
867
void ECA_CHAINSETUP::toggle_chain_muting(void)
 
868
{
 
869
  // ---
 
870
  DBC_REQUIRE(is_locked() != true);
 
871
  // ---
 
872
 
 
873
  for(vector<string>::const_iterator a = selected_chainids.begin(); a != selected_chainids.end(); a++) {
 
874
    for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
875
      if (*a == (*q)->name()) {
 
876
        if ((*q)->is_muted()) 
 
877
          (*q)->toggle_muting(false);
 
878
        else 
 
879
          (*q)->toggle_muting(true);
 
880
      }
 
881
    }
 
882
  }
 
883
}
 
884
 
 
885
/**
 
886
 * Toggles chain bypass of all selected chains.
 
887
 *
 
888
 * @pre is_locked() != true
 
889
 */
 
890
void ECA_CHAINSETUP::toggle_chain_bypass(void)
 
891
{
 
892
  // ---
 
893
  DBC_REQUIRE(is_locked() != true);
 
894
  // ---
 
895
 
 
896
  for(vector<string>::const_iterator a = selected_chainids.begin(); a != selected_chainids.end(); a++) {
 
897
    for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
898
      if (*a == (*q)->name()) {
 
899
        if ((*q)->is_processing()) 
 
900
          (*q)->toggle_processing(false);
 
901
        else 
 
902
          (*q)->toggle_processing(true);
 
903
      }
 
904
    }
 
905
  }
 
906
}
 
907
 
 
908
const ECA_CHAINSETUP_BUFPARAMS& ECA_CHAINSETUP::active_buffering_parameters(void) const 
 
909
{
 
910
  return impl_repp->bmode_active_rep;
 
911
}
 
912
 
 
913
const ECA_CHAINSETUP_BUFPARAMS& ECA_CHAINSETUP::override_buffering_parameters(void) const 
 
914
{
 
915
  return impl_repp->bmode_override_rep;
 
916
}
 
917
 
 
918
vector<string> ECA_CHAINSETUP::chain_names(void) const
 
919
{
 
920
  vector<string> result;
 
921
  vector<CHAIN*>::const_iterator p = chains.begin();
 
922
  while(p != chains.end()) {
 
923
    result.push_back((*p)->name());
 
924
    ++p;
 
925
  }
 
926
  return result;
 
927
}
 
928
 
 
929
vector<string> ECA_CHAINSETUP::audio_input_names(void) const
 
930
{
 
931
  vector<string> result;
 
932
  vector<AUDIO_IO*>::const_iterator p = inputs.begin();
 
933
  while(p != inputs.end()) {
 
934
    result.push_back((*p)->label());
 
935
    ++p;
 
936
  }
 
937
  return result;
 
938
}
 
939
 
 
940
vector<string> ECA_CHAINSETUP::audio_output_names(void) const
 
941
{
 
942
  vector<string> result;
 
943
  vector<AUDIO_IO*>::const_iterator p = outputs.begin();
 
944
  while(p != outputs.end()) {
 
945
    result.push_back((*p)->label());
 
946
    ++p;
 
947
  }
 
948
  return result;
 
949
}
 
950
 
 
951
vector<string> ECA_CHAINSETUP::get_attached_chains_to_input(AUDIO_IO* aiod) const 
 
952
 
953
  vector<string> res;
 
954
  
 
955
  vector<CHAIN*>::const_iterator q = chains.begin();
 
956
  while(q != chains.end()) {
 
957
    if (aiod == inputs[(*q)->connected_input()]) {
 
958
      res.push_back((*q)->name());
 
959
    }
 
960
    ++q;
 
961
  }
 
962
  
 
963
  return res; 
 
964
}
 
965
 
 
966
vector<string> ECA_CHAINSETUP::get_attached_chains_to_output(AUDIO_IO* aiod) const
 
967
 
968
  vector<string> res;
 
969
  
 
970
  vector<CHAIN*>::const_iterator q = chains.begin();
 
971
  while(q != chains.end()) {
 
972
    if (aiod == outputs[(*q)->connected_output()]) {
 
973
      res.push_back((*q)->name());
 
974
    }
 
975
    ++q;
 
976
  }
 
977
 
 
978
  return(res); 
 
979
}
 
980
 
 
981
int ECA_CHAINSETUP::number_of_attached_chains_to_input(AUDIO_IO* aiod) const
 
982
{
 
983
  int count = 0;
 
984
  
 
985
  vector<CHAIN*>::const_iterator q = chains.begin();
 
986
  while(q != chains.end()) {
 
987
    if (aiod == inputs[(*q)->connected_input()]) {
 
988
      ++count;
 
989
    }
 
990
    ++q;
 
991
  }
 
992
 
 
993
  return count; 
 
994
}
 
995
 
 
996
int ECA_CHAINSETUP::number_of_attached_chains_to_output(AUDIO_IO* aiod) const
 
997
{
 
998
  int count = 0;
 
999
  
 
1000
  vector<CHAIN*>::const_iterator q = chains.begin();
 
1001
  while(q != chains.end()) {
 
1002
    if (aiod == outputs[(*q)->connected_output()]) {
 
1003
      ++count;
 
1004
    }
 
1005
    ++q;
 
1006
  }
 
1007
 
 
1008
  return count; 
 
1009
}
 
1010
 
 
1011
/**
 
1012
 * Output object is realtime target if it is not 
 
1013
 * connected to any chains with non-realtime inputs.
 
1014
 * In other words all data coming to a rt target
 
1015
 * output comes from realtime devices.
 
1016
 */
 
1017
bool ECA_CHAINSETUP::is_realtime_target_output(int output_id) const
 
1018
{
 
1019
  bool result = true;
 
1020
  bool output_found = false;
 
1021
  vector<CHAIN*>::const_iterator q = chains.begin();
 
1022
  while(q != chains.end()) {
 
1023
    if ((*q)->connected_output() == output_id) {
 
1024
      output_found = true;
 
1025
      AUDIO_IO_DEVICE* p = dynamic_cast<AUDIO_IO_DEVICE*>(inputs[(*q)->connected_input()]);
 
1026
      if (p == 0) {
 
1027
        result = false;
 
1028
      }
 
1029
    }
 
1030
    ++q;
 
1031
  }
 
1032
  if (output_found == true && result == true) 
 
1033
    ECA_LOG_MSG(ECA_LOGGER::system_objects,"slave output detected: " + outputs[output_id]->label());
 
1034
  else
 
1035
    result = false;
 
1036
 
 
1037
  return result;
 
1038
}
 
1039
 
 
1040
vector<string> ECA_CHAINSETUP::get_attached_chains_to_iodev(const string& filename) const
 
1041
{
 
1042
  vector<AUDIO_IO*>::size_type p;
 
1043
 
 
1044
  p = 0;
 
1045
  while (p < inputs.size()) {
 
1046
    if (inputs[p]->label() == filename)
 
1047
      return get_attached_chains_to_input(inputs[p]);
 
1048
    ++p;
 
1049
  }
 
1050
 
 
1051
  p = 0;
 
1052
  while (p < outputs.size()) {
 
1053
    if (outputs[p]->label() == filename)
 
1054
      return get_attached_chains_to_output(outputs[p]);
 
1055
    ++p;
 
1056
  }
 
1057
  return vector<string> (0);
 
1058
}
 
1059
 
 
1060
/**
 
1061
 * Returns number of realtime audio input objects.
 
1062
 */
 
1063
int ECA_CHAINSETUP::number_of_chain_operators(void) const
 
1064
{
 
1065
  int cops = 0;
 
1066
  vector<CHAIN*>::const_iterator q = chains.begin();
 
1067
  while(q != chains.end()) {
 
1068
    cops += (*q)->number_of_chain_operators();
 
1069
    ++q;
 
1070
  }
 
1071
  return cops;
 
1072
}
 
1073
 
 
1074
/**
 
1075
 * Returns true if the connected chainsetup contains at least
 
1076
 * one realtime audio input or output.
 
1077
 */
 
1078
bool ECA_CHAINSETUP::has_realtime_objects(void) const
 
1079
{
 
1080
  if (number_of_realtime_inputs() > 0 ||
 
1081
      number_of_realtime_outputs() > 0) 
 
1082
    return true;
 
1083
 
 
1084
  return false;
 
1085
}
 
1086
 
 
1087
/**
 
1088
 * Returns true if the connected chainsetup contains at least
 
1089
 * one nonrealtime audio input or output.
 
1090
 */
 
1091
bool ECA_CHAINSETUP::has_nonrealtime_objects(void) const
 
1092
{
 
1093
  if (static_cast<int>(inputs_direct_rep.size() + outputs_direct_rep.size()) >
 
1094
      number_of_realtime_inputs() + number_of_realtime_outputs())
 
1095
    return true;
 
1096
  
 
1097
  return false;
 
1098
}
 
1099
 
 
1100
/**
 
1101
 * Returns a string containing currently active chainsetup
 
1102
 * options and settings. Syntax is the same as used for
 
1103
 * saved chainsetup files.
 
1104
 */
 
1105
string ECA_CHAINSETUP::options_to_string(void) const
 
1106
{
 
1107
  return cparser_rep.general_options_to_string();
 
1108
}
 
1109
 
 
1110
/**
 
1111
 * Returns number of realtime audio input objects.
 
1112
 */
 
1113
int ECA_CHAINSETUP::number_of_realtime_inputs(void) const
 
1114
{
 
1115
  int res = 0;
 
1116
  for(size_t n = 0; n < inputs_direct_rep.size(); n++) {
 
1117
    AUDIO_IO_DEVICE* p = dynamic_cast<AUDIO_IO_DEVICE*>(inputs_direct_rep[n]);
 
1118
    if (p != 0) res++;
 
1119
  }
 
1120
  return res;
 
1121
}
 
1122
 
 
1123
/**
 
1124
 * Returns number of realtime audio output objects.
 
1125
 */
 
1126
int ECA_CHAINSETUP::number_of_realtime_outputs(void) const
 
1127
{
 
1128
  int res = 0;
 
1129
  for(size_t n = 0; n < outputs_direct_rep.size(); n++) {
 
1130
    AUDIO_IO_DEVICE* p = dynamic_cast<AUDIO_IO_DEVICE*>(outputs_direct_rep[n]);
 
1131
    if (p != 0) res++;
 
1132
  }
 
1133
  return res;
 
1134
}
 
1135
 
 
1136
/**
 
1137
 * Returns number of non-realtime audio input objects.
 
1138
 */
 
1139
int ECA_CHAINSETUP::number_of_non_realtime_inputs(void) const
 
1140
{
 
1141
  return inputs.size() - number_of_realtime_inputs();
 
1142
}
 
1143
 
 
1144
/**
 
1145
 * Returns number of non-realtime audio input objects.
 
1146
 */
 
1147
int ECA_CHAINSETUP::number_of_non_realtime_outputs(void) const
 
1148
{
 
1149
  return outputs.size() - number_of_realtime_outputs();
 
1150
}
 
1151
 
 
1152
/**
 
1153
 * Returns a pointer to the manager handling audio object 'aobj'.
 
1154
 *
 
1155
 * @return 0 if 'aobj' is not handled by any manager
 
1156
 */
 
1157
AUDIO_IO_MANAGER* ECA_CHAINSETUP::get_audio_object_manager(AUDIO_IO* aio) const
 
1158
{
 
1159
  for(vector<AUDIO_IO_MANAGER*>::const_iterator q = aio_managers_rep.begin(); q != aio_managers_rep.end(); q++) {
 
1160
    if ((*q)->is_managed_type(aio) && 
 
1161
        (*q)->get_object_id(aio) != -1) {
 
1162
      ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
1163
                    "Found object manager \"" +
 
1164
                    (*q)->name() + 
 
1165
                    "\" for aio \"" +
 
1166
                    aio->label() + "\".");
 
1167
      
 
1168
      return *q;
 
1169
    }
 
1170
  }
 
1171
  return 0;
 
1172
}
 
1173
 
 
1174
/**
 
1175
 * Returns a pointer to the manager handling audio 
 
1176
 * objects of type 'aobj'.
 
1177
 *
 
1178
 * @return 0 if 'aobj' type is not handled by any manager
 
1179
 */
 
1180
AUDIO_IO_MANAGER* ECA_CHAINSETUP::get_audio_object_type_manager(AUDIO_IO* aio) const
 
1181
{
 
1182
  for(vector<AUDIO_IO_MANAGER*>::const_iterator q = aio_managers_rep.begin(); q != aio_managers_rep.end(); q++) {
 
1183
    if ((*q)->is_managed_type(aio) == true) {
 
1184
      ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
1185
                    "Found object manager \"" +
 
1186
                    (*q)->name() + 
 
1187
                    "\" for aio type \"" +
 
1188
                    aio->name() + "\".");
 
1189
      
 
1190
      return *q;
 
1191
    }
 
1192
  }
 
1193
  return 0;
 
1194
}
 
1195
 
 
1196
/**
 
1197
 * If 'amgr' implements the ECA_ENGINE_DRIVER interface, 
 
1198
 * it is registered as the active driver.
 
1199
 */
 
1200
void ECA_CHAINSETUP::register_engine_driver(AUDIO_IO_MANAGER* amgr)
 
1201
{
 
1202
  ECA_ENGINE_DRIVER* driver = dynamic_cast<ECA_ENGINE_DRIVER*>(amgr);
 
1203
 
 
1204
  if (driver != 0) {
 
1205
    engine_driver_repp = driver;
 
1206
    ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
1207
                  "Registered audio i/o manager \"" +
 
1208
                  amgr->name() +
 
1209
                  "\" as the current engine driver.");
 
1210
  }
 
1211
}
 
1212
 
 
1213
/**
 
1214
 * Registers audio object to a manager. If no managers are
 
1215
 * available for object's type, and it can create one,
 
1216
 * a new manager is created.
 
1217
 */
 
1218
void ECA_CHAINSETUP::register_audio_object_to_manager(AUDIO_IO* aio)
 
1219
{
 
1220
  AUDIO_IO_MANAGER* mgr = get_audio_object_type_manager(aio);
 
1221
  if (mgr == 0) {
 
1222
    mgr = aio->create_object_manager();
 
1223
    if (mgr != 0) {
 
1224
      ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
1225
                    "Creating object manager \"" +
 
1226
                    mgr->name() + 
 
1227
                    "\" for aio \"" +
 
1228
                    aio->name() + "\".");
 
1229
      aio_managers_rep.push_back(mgr);
 
1230
      propagate_audio_io_manager_options();
 
1231
      mgr->register_object(aio);
 
1232
 
 
1233
      /* in case manager is also a driver */
 
1234
      register_engine_driver(mgr);
 
1235
    }
 
1236
  }
 
1237
  else {
 
1238
    mgr->register_object(aio);
 
1239
  }
 
1240
}
 
1241
 
 
1242
/**
 
1243
 * Unregisters audio object from manager.
 
1244
 */
 
1245
void ECA_CHAINSETUP::unregister_audio_object_from_manager(AUDIO_IO* aio)
 
1246
{
 
1247
  AUDIO_IO_MANAGER* mgr = get_audio_object_manager(aio);
 
1248
  if (mgr != 0) {
 
1249
    int id = mgr->get_object_id(aio);
 
1250
    if (id != -1) {
 
1251
      ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
1252
                    "Unregistering object \"" +
 
1253
                    aio->name() + 
 
1254
                    "\" from manager \"" +
 
1255
                    mgr->name() + "\".");
 
1256
      mgr->unregister_object(id);
 
1257
    }
 
1258
  }
 
1259
}
 
1260
 
 
1261
/**
 
1262
 * Propagates to set manager options to all existing 
 
1263
 * audio i/o manager objects.
 
1264
 */
 
1265
void ECA_CHAINSETUP::propagate_audio_io_manager_options(void)
 
1266
{
 
1267
  for(vector<AUDIO_IO_MANAGER*>::const_iterator q = aio_managers_rep.begin(); q != aio_managers_rep.end(); q++) {
 
1268
    if (aio_manager_option_map_rep.find((*q)->name()) != 
 
1269
        aio_manager_option_map_rep.end()) {
 
1270
      
 
1271
      const string& optstring = aio_manager_option_map_rep[(*q)->name()];
 
1272
      int numparams = (*q)->number_of_params();
 
1273
      for(int n = 0; n < numparams; n++) {
 
1274
        (*q)->set_parameter(n + 1, kvu_get_argument_number(n + 1, optstring));
 
1275
        ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
1276
                    "Manager \"" +
 
1277
                    (*q)->name() + "\", " + 
 
1278
                    kvu_numtostr(n + 1) + ". parameter set to \"" +
 
1279
                    (*q)->get_parameter(n + 1) + "\".");
 
1280
      }
 
1281
    }      
 
1282
  }
 
1283
}
 
1284
 
 
1285
/** 
 
1286
 * Helper function used by add_input() and add_output().
 
1287
 * 
 
1288
 * All audio object creates go through this function,
 
1289
 * so this is good place to do global operations that
 
1290
 * apply to both inputs and outputs.
 
1291
 */
 
1292
AUDIO_IO* ECA_CHAINSETUP::add_audio_object_helper(AUDIO_IO* aio)
 
1293
{
 
1294
  AUDIO_IO* retobj = aio;
 
1295
  
 
1296
  AUDIO_IO_DEVICE* p = dynamic_cast<AUDIO_IO_DEVICE*>(aio);
 
1297
  LOOP_DEVICE* q = dynamic_cast<LOOP_DEVICE*>(aio);
 
1298
  if (p == 0 && q == 0) {
 
1299
    /* not a realtime or loop device */
 
1300
    retobj = new AUDIO_IO_DB_CLIENT(&impl_repp->pserver_rep, aio, false);
 
1301
    ++db_clients_rep;
 
1302
  }
 
1303
  return retobj;
 
1304
}
 
1305
 
 
1306
/** 
 
1307
 * Helper function used by remove_audio_object().
 
1308
 */
 
1309
void ECA_CHAINSETUP::remove_audio_object_proxy(AUDIO_IO* aio)
 
1310
{
 
1311
  AUDIO_IO_DB_CLIENT* p = dynamic_cast<AUDIO_IO_DB_CLIENT*>(aio);
 
1312
  if (p != 0) {
 
1313
    /* a proxied object */
 
1314
    ECA_LOG_MSG(ECA_LOGGER::user_objects, "Delete proxy object " + aio->label() + ".");
 
1315
    delete aio;
 
1316
    --db_clients_rep;
 
1317
  }
 
1318
}
 
1319
 
 
1320
/** 
 
1321
 * Helper function used bu remove_audio_object() to remove input 
 
1322
 * and output loop devices.
 
1323
 */
 
1324
void ECA_CHAINSETUP::remove_audio_object_loop(const string& label, AUDIO_IO* aio, int dir)
 
1325
{
 
1326
  int rdir = (dir == cs_dir_input ? cs_dir_output : cs_dir_input);
 
1327
 
 
1328
  /* loop devices are registered simultaneously to both input
 
1329
   * and output object vectors, so they have to be removed
 
1330
   * from both, but deleted only once */
 
1331
 
 
1332
  remove_audio_object_impl(label, rdir, false);
 
1333
 
 
1334
  /* we also need to remove the loop device from 
 
1335
   * the loop_map table */
 
1336
 
 
1337
  map<string,LOOP_DEVICE*>::iterator iter = loop_map.begin();
 
1338
  while(iter != loop_map.end()) {
 
1339
    if (iter->second == aio) {
 
1340
      loop_map.erase(iter);
 
1341
      break;
 
1342
    }
 
1343
    ++iter;
 
1344
  }
 
1345
}
 
1346
 
 
1347
/**
 
1348
 * Adds a new input object and attaches it to selected chains.
 
1349
 * 
 
1350
 * If double-buffering is enabled (double_buffering() == true),
 
1351
 * and the object in question is not a realtime object, it
 
1352
 * is wrapped in a AUDIO_IO_DB_CLIENT object before 
 
1353
 * inserted to the chainsetup. Otherwise object is added
 
1354
 * as is. 
 
1355
 * 
 
1356
 * Ownership of the insert object is transfered to 
 
1357
 * ECA_CHAINSETUP.
 
1358
 *
 
1359
 * @pre aiod != 0
 
1360
 * @pre is_enabled() != true
 
1361
 * @post inputs.size() == old(inputs.size() + 1
 
1362
 */
 
1363
void ECA_CHAINSETUP::add_input(AUDIO_IO* aio)
 
1364
{
 
1365
  // --------
 
1366
  DBC_REQUIRE(aio != 0);
 
1367
  DBC_REQUIRE(is_enabled() != true);
 
1368
  DBC_DECLARE(size_t old_inputs_size = inputs.size());
 
1369
  // --------
 
1370
 
 
1371
  aio->set_io_mode(AUDIO_IO::io_read);
 
1372
  aio->set_audio_format(default_audio_format());
 
1373
  aio->set_buffersize(buffersize());
 
1374
  
 
1375
  register_audio_object_to_manager(aio);
 
1376
  AUDIO_IO* layerobj = add_audio_object_helper(aio);
 
1377
  inputs.push_back(layerobj);
 
1378
  inputs_direct_rep.push_back(aio);
 
1379
  input_start_pos.push_back(0);
 
1380
  attach_input_to_selected_chains(layerobj);
 
1381
 
 
1382
  // --------
 
1383
  DBC_ENSURE(inputs.size() == old_inputs_size + 1);
 
1384
  DBC_ENSURE(inputs.size() == inputs_direct_rep.size());
 
1385
  // --------
 
1386
}
 
1387
 
 
1388
/**
 
1389
 * Add a new output object and attach it to selected chains.
 
1390
 * 
 
1391
 * If double-buffering is enabled (double_buffering() == true),
 
1392
 * and the object in question is not a realtime object, it
 
1393
 * is wrapped in a AUDIO_IO_DB_CLIENT object before 
 
1394
 * inserted to the chainsetup. Otherwise object is added
 
1395
 * as is. 
 
1396
 * 
 
1397
 * Ownership of the insert object is transfered to 
 
1398
 * ECA_CHAINSETUP.
 
1399
 *
 
1400
 * @pre aiod != 0
 
1401
 * @pre is_enabled() != true
 
1402
 * @post outputs.size() == outputs_direct_rep.size()
 
1403
 */
 
1404
void ECA_CHAINSETUP::add_output(AUDIO_IO* aio, bool truncate)
 
1405
{
 
1406
  // --------
 
1407
  DBC_REQUIRE(aio != 0);
 
1408
  DBC_REQUIRE(is_enabled() != true);
 
1409
  DBC_DECLARE(size_t old_outputs_size = outputs.size());
 
1410
  // --------
 
1411
 
 
1412
  aio->set_audio_format(default_audio_format());
 
1413
  aio->set_buffersize(buffersize());
 
1414
  if (truncate == true) 
 
1415
    aio->set_io_mode(AUDIO_IO::io_write);
 
1416
  else
 
1417
    aio->set_io_mode(AUDIO_IO::io_readwrite);
 
1418
 
 
1419
  register_audio_object_to_manager(aio);
 
1420
  AUDIO_IO* layerobj = add_audio_object_helper(aio);
 
1421
  outputs.push_back(layerobj);
 
1422
  outputs_direct_rep.push_back(aio);
 
1423
  output_start_pos.push_back(0);
 
1424
  attach_output_to_selected_chains(layerobj);
 
1425
 
 
1426
  // ---
 
1427
  DBC_ENSURE(outputs.size() == old_outputs_size + 1);
 
1428
  DBC_ENSURE(outputs.size() == outputs_direct_rep.size());
 
1429
  // ---
 
1430
}
 
1431
/**
 
1432
 * Erases an element matching 'obj' from 'vec'. At most one element
 
1433
 * is removed. The function does not delete the referred object, just
 
1434
 * removes it from the vector.
 
1435
 */ 
 
1436
static void priv_erase_object(std::vector<AUDIO_IO*>* vec, const AUDIO_IO* obj)
 
1437
{
 
1438
  vector<AUDIO_IO*>::iterator p = vec->begin();
 
1439
  while(p != vec->end()) {
 
1440
    if (*p == obj) {
 
1441
      vec->erase(p);
 
1442
      break;
 
1443
    }
 
1444
    ++p;
 
1445
  }
 
1446
}
 
1447
 
 
1448
/**
 
1449
 * Removes the labeled audio object from this chainsetup.
 
1450
 *
 
1451
 * @pre is_enabled() != true
 
1452
 */
 
1453
void ECA_CHAINSETUP::remove_audio_object_impl(const string& label, int dir, bool destroy)
 
1454
{
 
1455
  // ---
 
1456
  DBC_REQUIRE(is_enabled() != true);
 
1457
  // ---
 
1458
 
 
1459
  vector<AUDIO_IO*> *objs = (dir == cs_dir_input ? &inputs : &outputs);
 
1460
  vector<AUDIO_IO*> *objs_dir = (dir == cs_dir_input ? &inputs_direct_rep : &outputs_direct_rep);
 
1461
  DBC_DECLARE(size_t oldsize = objs->size());
 
1462
  AUDIO_IO *obj_to_remove = 0, *obj_dir_to_remove = NULL;
 
1463
  int remove_index = -1;
 
1464
 
 
1465
  /* Notes
 
1466
   *  - objs and objs_dir vectors are always of the same size
 
1467
   *  - for non-proxied objects 'objs[n] == objs_dir[n]' for all n
 
1468
   */
 
1469
 
 
1470
  for(size_t n = 0; n < objs->size(); n++) {
 
1471
    if ((*objs)[n]->label() == label) {
 
1472
      obj_to_remove = (*objs)[n];
 
1473
      obj_dir_to_remove = (*objs_dir)[n];
 
1474
      remove_index = static_cast<int>(n);
 
1475
    }
 
1476
  }
 
1477
 
 
1478
  if (obj_to_remove) {
 
1479
    DBC_CHECK(remove_index >= 0);
 
1480
    ECA_LOG_MSG(ECA_LOGGER::user_objects, "Removing object " + obj_to_remove->label() + ".");
 
1481
 
 
1482
    /* disconnect object from chains */
 
1483
    vector<CHAIN*>::iterator q = chains.begin();
 
1484
    while(q != chains.end()) {
 
1485
      if (dir == cs_dir_input) {
 
1486
        if ((*q)->connected_input() == remove_index) {
 
1487
          (*q)->disconnect_input();
 
1488
        }
 
1489
      }
 
1490
      else {
 
1491
        if ((*q)->connected_output() == remove_index) {
 
1492
          (*q)->disconnect_output();
 
1493
        }
 
1494
      }
 
1495
      ++q;
 
1496
    }
 
1497
 
 
1498
    /* unregister from manager (always the objs_dir object) */
 
1499
    unregister_audio_object_from_manager((*objs_dir)[remove_index]);
 
1500
 
 
1501
    /* delete proxy object if any */ 
 
1502
    if (obj_to_remove != obj_dir_to_remove) {
 
1503
      ECA_LOG_MSG(ECA_LOGGER::user_objects, "Audio object proxied: " + obj_to_remove->label());
 
1504
      remove_audio_object_proxy(obj_to_remove);
 
1505
    }
 
1506
   
 
1507
    priv_erase_object(objs, obj_to_remove);
 
1508
    priv_erase_object(objs_dir, obj_dir_to_remove);
 
1509
 
 
1510
    LOOP_DEVICE* loop_dev = dynamic_cast<LOOP_DEVICE*>(obj_dir_to_remove);
 
1511
    if (loop_dev != 0 && destroy == true) {
 
1512
      /* note: destroy must be true to limit recursion */
 
1513
      remove_audio_object_loop(label, obj_dir_to_remove, dir);
 
1514
    }
 
1515
 
 
1516
    /* finally actually delete the object */
 
1517
    if (destroy == true) 
 
1518
      delete obj_dir_to_remove;
 
1519
  }
 
1520
 
 
1521
  // ---
 
1522
  DBC_ENSURE(objs->size() == objs_dir->size());
 
1523
  DBC_ENSURE(oldsize == objs->size() + 1);
 
1524
  // ---
 
1525
}
 
1526
 
 
1527
/**
 
1528
 * Removes the labeled audio input from this chainsetup.
 
1529
 *
 
1530
 * @pre is_enabled() != true
 
1531
 */
 
1532
void ECA_CHAINSETUP::remove_audio_input(const string& label)
 
1533
{
 
1534
  // ---
 
1535
  DBC_REQUIRE(is_enabled() != true);
 
1536
  DBC_DECLARE(size_t oldsize = inputs.size());
 
1537
  // ---
 
1538
 
 
1539
  remove_audio_object_impl(label, cs_dir_input, true);
 
1540
 
 
1541
  // ---
 
1542
  DBC_ENSURE(inputs.size() == inputs_direct_rep.size());
 
1543
  DBC_ENSURE(oldsize == inputs.size() + 1);
 
1544
  // ---
 
1545
}
 
1546
 
 
1547
/**
 
1548
 * Removes the labeled audio output from this chainsetup.
 
1549
 *
 
1550
 * @pre is_enabled() != true
 
1551
 */
 
1552
void ECA_CHAINSETUP::remove_audio_output(const string& label)
 
1553
{
 
1554
  // --------
 
1555
  DBC_REQUIRE(is_enabled() != true);
 
1556
  DBC_DECLARE(size_t oldsize = outputs.size());
 
1557
  // --------
 
1558
 
 
1559
  remove_audio_object_impl(label, cs_dir_output, true);
 
1560
 
 
1561
  // ---
 
1562
  DBC_ENSURE(outputs.size() == outputs_direct_rep.size());
 
1563
  DBC_ENSURE(oldsize == outputs.size() + 1);
 
1564
  // ---
 
1565
}
 
1566
 
 
1567
/**
 
1568
 * Print trace messages when opening audio file 'aio'.
 
1569
 *
 
1570
 * @pre aio != 0
 
1571
 */
 
1572
void ECA_CHAINSETUP::audio_object_open_info(const AUDIO_IO* aio)
 
1573
{
 
1574
  // --------
 
1575
  DBC_REQUIRE(aio != 0);
 
1576
  // --------
 
1577
 
 
1578
  string temp = "Opened ";
 
1579
  
 
1580
  temp += (aio->io_mode() == AUDIO_IO::io_read) ? "input" : "output";
 
1581
  temp += " \"" + aio->label();
 
1582
  temp += "\", mode \"";
 
1583
  if (aio->io_mode() == AUDIO_IO::io_read) temp += "read";
 
1584
  if (aio->io_mode() == AUDIO_IO::io_write) temp += "write";
 
1585
  if (aio->io_mode() == AUDIO_IO::io_readwrite) temp += "read/write (update)";
 
1586
  temp += "\". ";
 
1587
  temp += aio->format_info();
 
1588
 
 
1589
  ECA_LOG_MSG(ECA_LOGGER::info, temp);
 
1590
}
 
1591
 
 
1592
 
 
1593
/**
 
1594
 * Adds a new MIDI-device object.
 
1595
 *
 
1596
 * @pre mididev != 0
 
1597
 * @pre is_enabled() != true
 
1598
 * @post midi_devices.size() > 0
 
1599
 */
 
1600
void ECA_CHAINSETUP::add_midi_device(MIDI_IO* mididev)
 
1601
{
 
1602
  // --------
 
1603
  DBC_REQUIRE(mididev != 0);
 
1604
  DBC_REQUIRE(is_enabled() != true);
 
1605
  // --------
 
1606
 
 
1607
  midi_devices.push_back(mididev);
 
1608
  impl_repp->midi_server_rep.register_client(mididev);
 
1609
 
 
1610
  // --------
 
1611
  DBC_ENSURE(midi_devices.size() > 0);
 
1612
  // --------
 
1613
}
 
1614
 
 
1615
/**
 
1616
 * Remove an MIDI-device by the name 'mdev_name'.
 
1617
 *
 
1618
 * @pre is_enabled() != true
 
1619
 */
 
1620
void ECA_CHAINSETUP::remove_midi_device(const string& mdev_name)
 
1621
{
 
1622
  // --------
 
1623
  DBC_REQUIRE(is_enabled() != true);
 
1624
  // --------
 
1625
 
 
1626
  for(vector<MIDI_IO*>::iterator q = midi_devices.begin(); q != midi_devices.end(); q++) {
 
1627
    if (mdev_name == (*q)->label()) {
 
1628
      delete *q;
 
1629
      midi_devices.erase(q);
 
1630
      break;
 
1631
    }
 
1632
  }
 
1633
}
 
1634
 
 
1635
const CHAIN* ECA_CHAINSETUP::get_chain_with_name(const string& name) const
 
1636
{
 
1637
  vector<CHAIN*>::const_iterator p = chains.begin();
 
1638
  while(p != chains.end()) {
 
1639
    if ((*p)->name() == name) return(*p);
 
1640
    ++p;
 
1641
  }
 
1642
  return 0;
 
1643
}
 
1644
 
 
1645
/**
 
1646
 * Returns a non-zero index for chain 'name'. If the chain
 
1647
 * does not exist, -1 is returned.
 
1648
 * 
 
1649
 * The chain index can be used with ECA::chainsetup_edit_t 
 
1650
 * items passed to ECA_CHAINSETUP::execute_edit().
 
1651
 *
 
1652
 * Note: Mapping of chain names to indices can change if any
 
1653
 *       chains are either added or removed. If that happens,
 
1654
 *       the indices need to be recalculated. 
 
1655
 */
 
1656
int ECA_CHAINSETUP::get_chain_index(const string& name) const
 
1657
{
 
1658
  int retval = -1;
 
1659
  vector<CHAIN*>::const_iterator p = chains.begin();
 
1660
  for(int n = 1; p != chains.end(); n++) {
 
1661
    if ((*p)->name() == name) {
 
1662
      retval = n;
 
1663
      break;
 
1664
    }
 
1665
    ++p;
 
1666
  }
 
1667
  return retval;
 
1668
}
 
1669
 
 
1670
/**
 
1671
 * Attaches input 'obj' to all selected chains.
 
1672
 *
 
1673
 * @pre is_locked() != true
 
1674
 */
 
1675
void ECA_CHAINSETUP::attach_input_to_selected_chains(const AUDIO_IO* obj)
 
1676
{
 
1677
  // --------
 
1678
  DBC_REQUIRE(obj != 0);
 
1679
  DBC_REQUIRE(is_locked() != true);
 
1680
  // --------
 
1681
 
 
1682
  string temp;
 
1683
  vector<AUDIO_IO*>::size_type c = 0;
 
1684
 
 
1685
  while (c < inputs.size()) {
 
1686
    if (inputs[c] == obj) {
 
1687
      for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
1688
        if ((*q)->connected_input() == static_cast<int>(c)) {
 
1689
          (*q)->disconnect_input();
 
1690
        }
 
1691
      }
 
1692
      temp += "Assigning file to chains:";
 
1693
      for(vector<string>::const_iterator p = selected_chainids.begin(); p!= selected_chainids.end(); p++) {
 
1694
        for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
1695
          if (*p == (*q)->name()) {
 
1696
            (*q)->connect_input(c);
 
1697
            temp += " " + *p;
 
1698
          }
 
1699
        }
 
1700
      }
 
1701
    }
 
1702
    ++c;
 
1703
  }
 
1704
  ECA_LOG_MSG(ECA_LOGGER::system_objects, temp);
 
1705
}
 
1706
 
 
1707
/**
 
1708
 * Attaches output 'obj' to all selected chains.
 
1709
 *
 
1710
 * @pre is_locked() != true
 
1711
 */
 
1712
void ECA_CHAINSETUP::attach_output_to_selected_chains(const AUDIO_IO* obj)
 
1713
{
 
1714
  // --------
 
1715
  DBC_REQUIRE(obj != 0);
 
1716
  DBC_REQUIRE(is_locked() != true);
 
1717
  // --------
 
1718
 
 
1719
  string temp;
 
1720
  vector<AUDIO_IO*>::size_type c = 0;
 
1721
  while (c < outputs.size()) {
 
1722
    if (outputs[c] == obj) {
 
1723
      for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
1724
        if ((*q)->connected_output() == static_cast<int>(c)) {
 
1725
          (*q)->disconnect_output();
 
1726
        }
 
1727
      }
 
1728
      temp += "Assigning file to chains:";
 
1729
      for(vector<string>::const_iterator p = selected_chainids.begin(); p!= selected_chainids.end(); p++) {
 
1730
        for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
1731
          if (*p == (*q)->name()) {
 
1732
            (*q)->connect_output(static_cast<int>(c));
 
1733
            temp += " " + *p;
 
1734
          }
 
1735
        }
 
1736
      }
 
1737
    }
 
1738
    ++c;
 
1739
  }
 
1740
  ECA_LOG_MSG(ECA_LOGGER::system_objects, temp);
 
1741
}
 
1742
 
 
1743
/**
 
1744
 * Returns true if 'aobj' is a pointer to some input
 
1745
 * or output object.
 
1746
 */
 
1747
bool ECA_CHAINSETUP::ok_audio_object(const AUDIO_IO* aobj) const
 
1748
{
 
1749
  if (ok_audio_object_helper(aobj, inputs) == true ||
 
1750
      ok_audio_object_helper(aobj, outputs) == true ) return(true);
 
1751
 
 
1752
  return false;
 
1753
  
 
1754
}
 
1755
 
 
1756
bool ECA_CHAINSETUP::ok_audio_object_helper(const AUDIO_IO* aobj,
 
1757
                                            const vector<AUDIO_IO*>& aobjs)
 
1758
{
 
1759
  for(size_t n = 0; n < aobjs.size(); n++) {
 
1760
    if (aobjs[n] == aobj) return(true);
 
1761
  }
 
1762
  return false;
 
1763
}
 
1764
 
 
1765
void ECA_CHAINSETUP::check_object_samplerate(const AUDIO_IO* obj,
 
1766
                                             SAMPLE_SPECS::sample_rate_t srate) throw(ECA_ERROR&)
 
1767
{
 
1768
  if (obj->samples_per_second() != srate) {
 
1769
    throw(ECA_ERROR("ECA-CHAINSETUP", 
 
1770
                    string("All audio objects must have a common") +
 
1771
                    " sampling rate; sampling rate of audio object \"" +
 
1772
                    obj->label() +
 
1773
                    "\" differs from engine rate (" +
 
1774
                    kvu_numtostr(obj->samples_per_second()) +
 
1775
                    " <-> " + 
 
1776
                    kvu_numtostr(srate) + 
 
1777
                    "); unable to continue."));
 
1778
  }
 
1779
}
 
1780
 
 
1781
void ECA_CHAINSETUP::enable_audio_object_helper(AUDIO_IO* aobj) const 
 
1782
{
 
1783
  aobj->set_buffersize(buffersize());
 
1784
  AUDIO_IO_DEVICE* dev = dynamic_cast<AUDIO_IO_DEVICE*>(aobj);
 
1785
  if (dev != 0) {
 
1786
    dev->toggle_max_buffers(max_buffers());
 
1787
    dev->toggle_ignore_xruns(ignore_xruns());
 
1788
  }
 
1789
  if (aobj->is_open() == false) {
 
1790
    const std::string req_format = ECA_OBJECT_FACTORY::audio_object_format_to_eos(aobj);
 
1791
    aobj->open();
 
1792
    const std::string act_format =
 
1793
      ECA_OBJECT_FACTORY::audio_object_format_to_eos(aobj);
 
1794
    if (act_format != req_format) {
 
1795
      DBC_CHECK(aobj->locked_audio_format() == true);
 
1796
      ECA_LOG_MSG(ECA_LOGGER::info, 
 
1797
                  "NOTE: using existing audio parameters " + act_format +
 
1798
                  " for object '" + aobj->label() + "' (tried to open with " +
 
1799
                  req_format + ").");
 
1800
    }
 
1801
  }
 
1802
  if (aobj->is_open() == true) {
 
1803
    aobj->seek_position_in_samples(aobj->position_in_samples());
 
1804
    audio_object_open_info(aobj);
 
1805
  }
 
1806
}
 
1807
 
 
1808
/**
 
1809
 * Enable chainsetup. Opens all devices and reinitializes all 
 
1810
 * chain operators if necessary.
 
1811
 *
 
1812
 * This action is performed before connecting the chainsetup
 
1813
 * to a engine object (for instance ECA_ENGINE). 
 
1814
 * 
 
1815
 * @pre is_locked() != true
 
1816
 * @post is_enabled() == true
 
1817
 */
 
1818
void ECA_CHAINSETUP::enable(void) throw(ECA_ERROR&)
 
1819
{
 
1820
  // --------
 
1821
  DBC_REQUIRE(is_locked() != true);
 
1822
  // --------
 
1823
 
 
1824
  try {
 
1825
    if (is_enabled_rep != true) {
 
1826
 
 
1827
      /* 1. check that current buffersize is supported by all devices */
 
1828
      long int locked_bsize = check_for_locked_buffersize();
 
1829
      if (locked_bsize != -1) {
 
1830
        set_buffersize(locked_bsize);
 
1831
      }
 
1832
 
 
1833
      /* 2. select and enable buffering parameters */
 
1834
      select_active_buffering_mode();
 
1835
      enable_active_buffering_mode();
 
1836
 
 
1837
      /* 3.1 open input devices */
 
1838
      for(vector<AUDIO_IO*>::iterator q = inputs.begin(); q != inputs.end(); q++) {
 
1839
        enable_audio_object_helper(*q);
 
1840
        if ((*q)->is_open() != true) { 
 
1841
          throw(ECA_ERROR("ECA-CHAINSETUP", "Open failed without explicit exception!"));
 
1842
        }
 
1843
      }
 
1844
 
 
1845
      /* 3.2. make sure that all input devices have a common 
 
1846
       *      sampling rate */
 
1847
      SAMPLE_SPECS::sample_rate_t first_locked_srate = 0;
 
1848
      for(vector<AUDIO_IO*>::iterator q = inputs.begin(); q != inputs.end(); q++) {
 
1849
        if (first_locked_srate == 0) {
 
1850
          if ((*q)->locked_audio_format() == true) {
 
1851
            first_locked_srate = (*q)->samples_per_second();
 
1852
 
 
1853
            /* set chainsetup sampling rate to 'first_srate'. */
 
1854
            set_samples_per_second(first_locked_srate);
 
1855
          }
 
1856
        }
 
1857
        else {
 
1858
          check_object_samplerate(*q, first_locked_srate);
 
1859
        }
 
1860
      }
 
1861
 
 
1862
      /* 4. open output devices */
 
1863
      for(vector<AUDIO_IO*>::iterator q = outputs.begin(); q != outputs.end(); q++) {
 
1864
        enable_audio_object_helper(*q);
 
1865
        if ((*q)->is_open() != true) { 
 
1866
          throw(ECA_ERROR("ECA-CHAINSETUP", "Open failed without explicit exception!"));
 
1867
        }
 
1868
        if (first_locked_srate == 0) {
 
1869
          if ((*q)->locked_audio_format() == true) {
 
1870
            first_locked_srate = (*q)->samples_per_second();
 
1871
 
 
1872
            /* set chainsetup sampling rate to 'first_srate'. */
 
1873
            set_samples_per_second(first_locked_srate);
 
1874
          }
 
1875
        }
 
1876
        else {
 
1877
          check_object_samplerate(*q, first_locked_srate);
 
1878
        }
 
1879
      }
 
1880
 
 
1881
      /* 5. in case there were no objects with locked srates */
 
1882
      if (first_locked_srate == 0) {
 
1883
        if (inputs.size() > 0) {
 
1884
          /* set chainsetup srate to that of the first input */
 
1885
          set_samples_per_second(inputs[0]->samples_per_second());
 
1886
        }
 
1887
      }
 
1888
 
 
1889
      /* 6. enable the MIDI server */
 
1890
      if (impl_repp->midi_server_rep.is_enabled() != true &&
 
1891
          midi_devices.size() > 0) {
 
1892
        impl_repp->midi_server_rep.set_schedrealtime(raised_priority());
 
1893
        impl_repp->midi_server_rep.set_schedpriority(get_sched_priority());
 
1894
        impl_repp->midi_server_rep.enable();
 
1895
      }
 
1896
 
 
1897
      /* 7. enable all MIDI-devices */
 
1898
      for(vector<MIDI_IO*>::iterator q = midi_devices.begin(); q != midi_devices.end(); q++) {
 
1899
        (*q)->toggle_nonblocking_mode(true);
 
1900
        if ((*q)->is_open() != true) {
 
1901
          (*q)->open();
 
1902
          if ((*q)->is_open() != true) {
 
1903
            throw(ECA_ERROR("ECA-CHAINSETUP", 
 
1904
                            string("Unable to open MIDI-device: ") +
 
1905
                            (*q)->label() +
 
1906
                            "."));
 
1907
          }
 
1908
        }
 
1909
      }
 
1910
 
 
1911
      /* 8. calculate chainsetup length */
 
1912
      calculate_processing_length();
 
1913
 
 
1914
    }
 
1915
    is_enabled_rep = true;
 
1916
  }
 
1917
  catch(AUDIO_IO::SETUP_ERROR& e) {
 
1918
    ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
1919
                "Connecting chainsetup failed, throwing an SETUP_ERROR exception.");
 
1920
    throw(ECA_ERROR("ECA-CHAINSETUP", 
 
1921
                    string("Enabling chainsetup: ")
 
1922
                    + e.message()));
 
1923
  }
 
1924
  catch(...) { 
 
1925
    ECA_LOG_MSG(ECA_LOGGER::system_objects, 
 
1926
                "Connecting chainsetup failed, throwing a generic exception.");
 
1927
    throw; 
 
1928
  }
 
1929
 
 
1930
  // --------
 
1931
  DBC_ENSURE(is_enabled() == true);
 
1932
  // --------
 
1933
}
 
1934
 
 
1935
 
 
1936
 
 
1937
/**
 
1938
 * Disable chainsetup. Closes all devices. 
 
1939
 * 
 
1940
 * This action is performed before disconnecting the 
 
1941
 * chainsetup from a engine object (for instance 
 
1942
 * ECA_ENGINE). 
 
1943
 * 
 
1944
 * @pre is_locked() != true
 
1945
 * @post is_enabled() != true
 
1946
 */
 
1947
void ECA_CHAINSETUP::disable(void)
 
1948
{
 
1949
  // --------
 
1950
  DBC_REQUIRE(is_locked() != true);
 
1951
  // --------
 
1952
 
 
1953
  /* calculate chainsetup length in case it has changed during processing */
 
1954
  calculate_processing_length();
 
1955
 
 
1956
  if (is_enabled_rep == true) {
 
1957
    ECA_LOG_MSG(ECA_LOGGER::system_objects, "Closing chainsetup \"" + name() + "\"");
 
1958
    for(vector<AUDIO_IO*>::iterator q = inputs.begin(); q != inputs.end(); q++) {
 
1959
      ECA_LOG_MSG(ECA_LOGGER::system_objects, "Closing audio device/file \"" + (*q)->label() + "\".");
 
1960
      if ((*q)->is_open() == true) (*q)->close();
 
1961
    }
 
1962
    
 
1963
    for(vector<AUDIO_IO*>::iterator q = outputs.begin(); q != outputs.end(); q++) {
 
1964
      ECA_LOG_MSG(ECA_LOGGER::system_objects, "Closing audio device/file \"" + (*q)->label() + "\".");
 
1965
      if ((*q)->is_open() == true) (*q)->close();
 
1966
    }
 
1967
 
 
1968
    if (impl_repp->midi_server_rep.is_enabled() == true) impl_repp->midi_server_rep.disable();
 
1969
    for(vector<MIDI_IO*>::iterator q = midi_devices.begin(); q != midi_devices.end(); q++) {
 
1970
      ECA_LOG_MSG(ECA_LOGGER::system_objects, "Closing midi device \"" + (*q)->label() + "\".");
 
1971
      if ((*q)->is_open() == true) (*q)->close();
 
1972
    }
 
1973
 
 
1974
    is_enabled_rep = false;
 
1975
  }
 
1976
 
 
1977
  // --------
 
1978
  DBC_ENSURE(is_enabled() != true);
 
1979
  // --------
 
1980
}
 
1981
 
 
1982
/**
 
1983
 * Executes chainsetup edit 'edit'.
 
1984
 *
 
1985
 * @return true if succesful, false if edit cannot
 
1986
 *         be performed
 
1987
 */
 
1988
bool ECA_CHAINSETUP::execute_edit(const chainsetup_edit_t& edit)
 
1989
{
 
1990
  bool retval = true;
 
1991
 
 
1992
  ECA_LOG_MSG(ECA_LOGGER::user_objects,
 
1993
              "Executing edit type of " +
 
1994
              kvu_numtostr(static_cast<int>(edit.type)));
 
1995
 
 
1996
  if (edit.cs_ptr != this) {
 
1997
    ECA_LOG_MSG(ECA_LOGGER::errors, 
 
1998
                "ERROR: chainsetup edit executed on wrong object");
 
1999
    return false;
 
2000
  }
 
2001
 
 
2002
  switch(edit.type)
 
2003
    {
 
2004
    case edit_cop_set_param:
 
2005
      {
 
2006
        if (edit.m.cop_set_param.chain < 1 ||
 
2007
            edit.m.cop_set_param.chain > static_cast<int>(chains.size())) {
 
2008
          retval = false;
 
2009
          break;
 
2010
        }
 
2011
        CHAIN *ch = chains[edit.m.cop_set_param.chain - 1];
 
2012
        ch->set_parameter(edit.m.cop_set_param.op, 
 
2013
                          edit.m.cop_set_param.param,
 
2014
                          edit.m.cop_set_param.value);
 
2015
        break;
 
2016
      }
 
2017
    case edit_ctrl_set_param:
 
2018
      {
 
2019
        if (edit.m.ctrl_set_param.chain < 1 ||
 
2020
            edit.m.ctrl_set_param.chain > static_cast<int>(chains.size())) {
 
2021
          retval = false;
 
2022
          break;
 
2023
        }
 
2024
        CHAIN *ch = chains[edit.m.ctrl_set_param.chain - 1];
 
2025
        ch->set_controller_parameter(edit.m.ctrl_set_param.op,
 
2026
                                     edit.m.ctrl_set_param.param,
 
2027
                                     edit.m.ctrl_set_param.value);
 
2028
        break;
 
2029
      }
 
2030
    default:
 
2031
      {
 
2032
        DBC_NEVER_REACHED();
 
2033
        retval = false;
 
2034
        ECA_LOG_MSG(ECA_LOGGER::info,
 
2035
                    "Unknown edit of type " +
 
2036
                    kvu_numtostr(static_cast<int>(edit.type)));
 
2037
        break;
 
2038
      }
 
2039
    }
 
2040
 
 
2041
  return retval;
 
2042
}
 
2043
 
 
2044
/**
 
2045
 * Updates the chainsetup processing length based on 
 
2046
 * 1) requested length, 2) lengths of individual 
 
2047
 * input objects, and 3) looping settings.
 
2048
 */
 
2049
void ECA_CHAINSETUP::calculate_processing_length(void)
 
2050
{
 
2051
  long int max_input_length = 0;
 
2052
  for(unsigned int n = 0; n < inputs.size(); n++) {
 
2053
    if (inputs[n]->length_in_samples() > max_input_length)
 
2054
      max_input_length = inputs[n]->length_in_samples();
 
2055
  }
 
2056
  
 
2057
  /* note! here we set the _actual_ length of the 
 
2058
   *       chainsetup */
 
2059
  set_length_in_samples(max_input_length);
 
2060
 
 
2061
  if (looping_enabled() == true) {
 
2062
    if (max_length_set() != true &&
 
2063
        max_input_length > 0) {
 
2064
      /* looping but length not set */
 
2065
      ECA_LOG_MSG(ECA_LOGGER::info, 
 
2066
                  "Setting loop point to "
 
2067
                   + kvu_numtostr(length_in_seconds_exact()) + ".");
 
2068
      set_max_length_in_samples(max_input_length);
 
2069
    }
 
2070
  }
 
2071
}
 
2072
 
 
2073
/**
 
2074
 * Check whether the buffersize is locked to some 
 
2075
 * specific value.
 
2076
 *
 
2077
 * @return -1 if not locked, otherwise the locked
 
2078
 *         value
 
2079
 */
 
2080
long int ECA_CHAINSETUP::check_for_locked_buffersize(void) const
 
2081
{
 
2082
  long int result = -1;
 
2083
#ifdef ECA_COMPILE_JACK
 
2084
  int pid = getpid();
 
2085
  string cname = "ecasound-ctrl-" + kvu_numtostr(pid);
 
2086
  int jackobjs = 0;
 
2087
 
 
2088
  for(size_t n = 0; n < inputs_direct_rep.size(); n++) {
 
2089
    if (inputs_direct_rep[n]->name() == "JACK interface") ++jackobjs;
 
2090
  }
 
2091
  for(size_t n = 0; n < outputs_direct_rep.size(); n++) {
 
2092
    if (outputs_direct_rep[n]->name() == "JACK interface") ++jackobjs;
 
2093
  }
 
2094
 
 
2095
  /* contact jackd only if there is at least one jack audio object 
 
2096
   * present */
 
2097
  if (jackobjs > 0) {
 
2098
    jack_client_t *client = jack_client_open(cname.c_str(), JackNullOption, NULL);
 
2099
    if (client != 0) {
 
2100
      // xxx = static_cast<long int>(jack_get_sample_rate(client);
 
2101
      result = static_cast<long int>(jack_get_buffer_size(client));
 
2102
      
 
2103
      ECA_LOG_MSG(ECA_LOGGER::user_objects,
 
2104
                "jackd buffersize check returned " +
 
2105
                  kvu_numtostr(result) + ".");
 
2106
      
 
2107
      jack_client_close(client);
 
2108
      
 
2109
      client = 0;
 
2110
    }
 
2111
    else {
 
2112
      ECA_LOG_MSG(ECA_LOGGER::user_objects,
 
2113
                  "unable to perform jackd buffersize check.");
 
2114
    }
 
2115
    
 
2116
    DBC_CHECK(client == 0);
 
2117
  }
 
2118
#endif
 
2119
  return result;
 
2120
}
 
2121
 
 
2122
/**
 
2123
 * Reimplemented from ECA_CHAINSETUP_POSITION.
 
2124
 */
 
2125
void ECA_CHAINSETUP::set_samples_per_second(SAMPLE_SPECS::sample_rate_t new_value)
 
2126
{
 
2127
  /* not necessarily a problem */
 
2128
  DBC_CHECK(is_locked() != true);
 
2129
 
 
2130
  ECA_LOG_MSG(ECA_LOGGER::user_objects,
 
2131
                "sample rate change, chainsetup " +
 
2132
                name() +
 
2133
                " to rate " + 
 
2134
                kvu_numtostr(new_value) + ".");
 
2135
 
 
2136
  for(vector<AUDIO_IO*>::iterator q = inputs.begin(); q != inputs.end(); q++) {
 
2137
    (*q)->set_samples_per_second(new_value);
 
2138
  }
 
2139
  
 
2140
  for(vector<AUDIO_IO*>::iterator q = outputs.begin(); q != outputs.end(); q++) {
 
2141
    (*q)->set_samples_per_second(new_value);
 
2142
  }
 
2143
 
 
2144
  for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
2145
    (*q)->set_samples_per_second(new_value);
 
2146
  }
 
2147
  
 
2148
  ECA_CHAINSETUP_POSITION::set_samples_per_second(new_value);
 
2149
}
 
2150
 
 
2151
static void priv_seek_position_helper(std::vector<AUDIO_IO*>* objs, SAMPLE_SPECS::sample_pos_t pos, const std::string& tag)
 
2152
{
 
2153
  for(vector<AUDIO_IO*>::iterator q = objs->begin(); q != objs->end(); q++) {
 
2154
    /* note: don't try to seek real-time devices (only
 
2155
     *       allowed exception, try seeking all other
 
2156
     *       objects */
 
2157
    if (dynamic_cast<AUDIO_IO_DEVICE*>(*q) == 0) { 
 
2158
      (*q)->seek_position_in_samples(pos);
 
2159
      /* note: report if object claims it supports seeking, but
 
2160
       *       in fact the seek failed */
 
2161
      if ((*q)->supports_seeking() == true) {
 
2162
        if (pos <= (*q)->length_in_samples() &&
 
2163
            (*q)->position_in_samples() != pos)
 
2164
          ECA_LOG_MSG(ECA_LOGGER::info,
 
2165
                      "WARNING: sample accurate seek failed with " +
 
2166
                      tag + " \"" + (*q)->name() + "\"");
 
2167
      }
 
2168
    }
 
2169
  }
 
2170
}
 
2171
 
 
2172
/**
 
2173
 * Reimplemented from ECA_AUDIO_POSITION.
 
2174
 */
 
2175
SAMPLE_SPECS::sample_pos_t ECA_CHAINSETUP::seek_position(SAMPLE_SPECS::sample_pos_t pos)
 
2176
{
 
2177
  ECA_LOG_MSG(ECA_LOGGER::user_objects,
 
2178
              "seek position, chainsetup \"" +
 
2179
              name() +
 
2180
              "\" to pos in sec " + 
 
2181
              kvu_numtostr(pos) + ".");
 
2182
 
 
2183
  if (is_enabled() == true) {
 
2184
    if (double_buffering() == true) pserver_repp->flush();
 
2185
  }
 
2186
 
 
2187
  priv_seek_position_helper(&inputs, pos, "input");
 
2188
  priv_seek_position_helper(&outputs, pos, "output");
 
2189
 
 
2190
  for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
2191
    (*q)->seek_position_in_samples(pos);
 
2192
    if ((*q)->position_in_samples() != pos)
 
2193
      ECA_LOG_MSG(ECA_LOGGER::info,
 
2194
                  "WARNING: sample accurate seek failed with chainop \"" +
 
2195
                  (*q)->name() + "\"");
 
2196
    
 
2197
  }
 
2198
 
 
2199
  return pos;
 
2200
}
 
2201
 
 
2202
/**
 
2203
 * Interprets one option. This is the most generic variant of
 
2204
 * the interpretation routines; both global and object specific
 
2205
 * options are handled.
 
2206
 *
 
2207
 * @pre argu.size() > 0
 
2208
 * @pre argu[0] == '-'
 
2209
 * @pre is_enabled() != true
 
2210
 * 
 
2211
 * @post (option successfully interpreted && interpret_result() ==  true) ||
 
2212
 *       (unknown or invalid option && interpret_result() != true)
 
2213
 */
 
2214
void ECA_CHAINSETUP::interpret_option (const string& arg)
 
2215
{
 
2216
  // --------
 
2217
  DBC_REQUIRE(is_enabled() != true);
 
2218
  // --------
 
2219
 
 
2220
  cparser_rep.interpret_option(arg);
 
2221
}
 
2222
 
 
2223
/**
 
2224
 * Interprets one option. All non-global options are ignored. Global
 
2225
 * options can be interpreted multiple times and in any order.
 
2226
 *
 
2227
 * @pre argu.size() > 0
 
2228
 * @pre argu[0] == '-'
 
2229
 * @pre is_enabled() != true
 
2230
 * @post (option successfully interpreted && interpretation_result() ==  true) ||
 
2231
 *       (unknown or invalid option && interpretation_result() == false)
 
2232
 */
 
2233
void ECA_CHAINSETUP::interpret_global_option (const string& arg)
 
2234
{
 
2235
  // --------
 
2236
  DBC_REQUIRE(is_enabled() != true);
 
2237
  // --------
 
2238
 
 
2239
  cparser_rep.interpret_global_option(arg);
 
2240
}
 
2241
 
 
2242
/**
 
2243
 * Interprets one option. All options not directly related to 
 
2244
 * ecasound objects are ignored.
 
2245
 *
 
2246
 * @pre argu.size() > 0
 
2247
 * @pre argu[0] == '-'
 
2248
 * @pre is_enabled() != true
 
2249
 * 
 
2250
 * @post (option successfully interpreted && interpretation_result() ==  true) ||
 
2251
 *       (unknown or invalid option && interpretation_result() == false)
 
2252
 */
 
2253
void ECA_CHAINSETUP::interpret_object_option (const string& arg)
 
2254
{
 
2255
  // --------
 
2256
  // FIXME: this requirement is broken by eca-control.h (for 
 
2257
  //        adding effects on-the-fly, just stopping the engine)
 
2258
  // DBC_REQUIRE(is_enabled() != true);
 
2259
  // --------
 
2260
 
 
2261
  cparser_rep.interpret_object_option(arg);
 
2262
}
 
2263
 
 
2264
/**
 
2265
 * Interpret a vector of options.
 
2266
 *
 
2267
 * If any invalid options are passed us argument, 
 
2268
 * interpret_result() will be 'false', and 
 
2269
 * interpret_result_verbose() contains more detailed 
 
2270
 * error description.
 
2271
 *
 
2272
 * @pre is_enabled() != true
 
2273
 */
 
2274
void ECA_CHAINSETUP::interpret_options(const vector<string>& opts)
 
2275
{
 
2276
  // --------
 
2277
  DBC_REQUIRE(is_enabled() != true);
 
2278
  // --------
 
2279
 
 
2280
  cparser_rep.interpret_options(opts);
 
2281
}
 
2282
 
 
2283
void ECA_CHAINSETUP::set_buffersize(long int value)
 
2284
{
 
2285
  ECA_LOG_MSG(ECA_LOGGER::system_objects, "overriding buffersize.");
 
2286
  impl_repp->bmode_override_rep.set_buffersize(value); 
 
2287
}
 
2288
 
 
2289
void ECA_CHAINSETUP::toggle_raised_priority(bool value) { 
 
2290
  ECA_LOG_MSG(ECA_LOGGER::system_objects, "overriding raised priority.");
 
2291
  impl_repp->bmode_override_rep.toggle_raised_priority(value); 
 
2292
}
 
2293
 
 
2294
void ECA_CHAINSETUP::set_sched_priority(int value)
 
2295
{
 
2296
  ECA_LOG_MSG(ECA_LOGGER::system_objects, "sched_priority.");
 
2297
  impl_repp->bmode_override_rep.set_sched_priority(value); 
 
2298
}
 
2299
 
 
2300
void ECA_CHAINSETUP::toggle_double_buffering(bool value)
 
2301
{
 
2302
  ECA_LOG_MSG(ECA_LOGGER::system_objects, "overriding doublebuffering.");
 
2303
  impl_repp->bmode_override_rep.toggle_double_buffering(value); 
 
2304
}
 
2305
 
 
2306
void ECA_CHAINSETUP::set_double_buffer_size(long int v)
 
2307
{
 
2308
  ECA_LOG_MSG(ECA_LOGGER::system_objects, "overriding db-size.");
 
2309
  impl_repp->bmode_override_rep.set_double_buffer_size(v); 
 
2310
}
 
2311
 
 
2312
void ECA_CHAINSETUP::toggle_max_buffers(bool v)
 
2313
{
 
2314
  ECA_LOG_MSG(ECA_LOGGER::system_objects, "overriding max_buffers.");
 
2315
  impl_repp->bmode_override_rep.toggle_max_buffers(v); 
 
2316
}
 
2317
 
 
2318
long int ECA_CHAINSETUP::buffersize(void) const
 
2319
{
 
2320
  if (impl_repp->bmode_override_rep.is_set_buffersize() == true)
 
2321
    return impl_repp->bmode_override_rep.buffersize();
 
2322
  
 
2323
  return impl_repp->bmode_active_rep.buffersize(); 
 
2324
}
 
2325
 
 
2326
bool ECA_CHAINSETUP::raised_priority(void) const
 
2327
{
 
2328
  if (impl_repp->bmode_override_rep.is_set_raised_priority() == true)
 
2329
    return impl_repp->bmode_override_rep.raised_priority();
 
2330
 
 
2331
  return impl_repp->bmode_active_rep.raised_priority(); 
 
2332
}
 
2333
 
 
2334
int ECA_CHAINSETUP::get_sched_priority(void) const
 
2335
{
 
2336
  if (impl_repp->bmode_override_rep.is_set_sched_priority() == true)
 
2337
    return impl_repp->bmode_override_rep.get_sched_priority();
 
2338
 
 
2339
  return impl_repp->bmode_active_rep.get_sched_priority(); 
 
2340
}
 
2341
 
 
2342
bool ECA_CHAINSETUP::double_buffering(void) const { 
 
2343
  if (impl_repp->bmode_override_rep.is_set_double_buffering() == true)
 
2344
    return impl_repp->bmode_override_rep.double_buffering();
 
2345
 
 
2346
  return impl_repp->bmode_active_rep.double_buffering(); 
 
2347
}
 
2348
 
 
2349
long int ECA_CHAINSETUP::double_buffer_size(void) const { 
 
2350
  if (impl_repp->bmode_override_rep.is_set_double_buffer_size() == true)
 
2351
    return impl_repp->bmode_override_rep.double_buffer_size();
 
2352
 
 
2353
  return impl_repp->bmode_active_rep.double_buffer_size(); 
 
2354
}
 
2355
 
 
2356
bool ECA_CHAINSETUP::max_buffers(void) const { 
 
2357
  if (impl_repp->bmode_override_rep.is_set_max_buffers() == true)
 
2358
    return impl_repp->bmode_override_rep.max_buffers();
 
2359
 
 
2360
  return impl_repp->bmode_active_rep.max_buffers(); 
 
2361
}
 
2362
 
 
2363
void ECA_CHAINSETUP::set_default_audio_format(ECA_AUDIO_FORMAT& value) { 
 
2364
  impl_repp->default_audio_format_rep = value; 
 
2365
}
 
2366
 
 
2367
const ECA_AUDIO_FORMAT& ECA_CHAINSETUP::default_audio_format(void) const
 
2368
 
2369
  return impl_repp->default_audio_format_rep; 
 
2370
}
 
2371
 
 
2372
/**
 
2373
 * Select controllers as targets for parameter control
 
2374
 */
 
2375
void ECA_CHAINSETUP::set_target_to_controller(void) {
 
2376
  vector<string> schains = selected_chains();
 
2377
  for(vector<string>::const_iterator a = schains.begin(); a != schains.end(); a++) {
 
2378
    for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
2379
      if (*a == (*q)->name()) {
 
2380
        (*q)->selected_controller_as_target();
 
2381
        return;
 
2382
      }
 
2383
    }
 
2384
  }
 
2385
}
 
2386
 
 
2387
/**
 
2388
 * Add general controller to selected chainop.
 
2389
 *
 
2390
 * @pre csrc != 0
 
2391
 * @pre is_locked() != true
 
2392
 * @pre selected_chains().size() == 1
 
2393
 */
 
2394
void ECA_CHAINSETUP::add_controller(GENERIC_CONTROLLER* csrc)
 
2395
{
 
2396
  // --------
 
2397
  DBC_REQUIRE(csrc != 0);
 
2398
  DBC_REQUIRE(is_locked() != true);
 
2399
  DBC_REQUIRE(selected_chains().size() == 1);
 
2400
  // --------
 
2401
 
 
2402
#ifndef ECA_DISABLE_EFFECTS
 
2403
  AUDIO_STAMP_CLIENT* p = dynamic_cast<AUDIO_STAMP_CLIENT*>(csrc->source_pointer());
 
2404
  if (p != 0) {
 
2405
    p->register_server(&impl_repp->stamp_server_rep);
 
2406
  }
 
2407
#endif
 
2408
 
 
2409
  DBC_CHECK(buffersize() != 0);
 
2410
  DBC_CHECK(samples_per_second() != 0);
 
2411
 
 
2412
  vector<string> schains = selected_chains();
 
2413
  for(vector<string>::const_iterator a = schains.begin(); a != schains.end(); a++) {
 
2414
    for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
2415
      if (*a == (*q)->name()) {
 
2416
        if ((*q)->selected_target() == 0) return;
 
2417
        (*q)->add_controller(csrc);
 
2418
        return;
 
2419
      }
 
2420
    }
 
2421
  }
 
2422
}
 
2423
 
 
2424
/**
 
2425
 * Add chain operator to selected chain.
 
2426
 *
 
2427
 * @pre cotmp != 0
 
2428
 * @pre is_locked() != true
 
2429
 * @pre selected_chains().size() == 1
 
2430
 */
 
2431
void ECA_CHAINSETUP::add_chain_operator(CHAIN_OPERATOR* cotmp)
 
2432
{
 
2433
  // --------
 
2434
  DBC_REQUIRE(cotmp != 0);
 
2435
  DBC_REQUIRE(is_locked() != true);
 
2436
  DBC_REQUIRE(selected_chains().size() == 1);
 
2437
  // --------
 
2438
  
 
2439
#ifndef ECA_DISABLE_EFFECTS
 
2440
  AUDIO_STAMP* p = dynamic_cast<AUDIO_STAMP*>(cotmp);
 
2441
  if (p != 0) {
 
2442
    impl_repp->stamp_server_rep.register_stamp(p);
 
2443
  }
 
2444
#endif
 
2445
 
 
2446
  vector<string> schains = selected_chains();
 
2447
  for(vector<string>::const_iterator p = schains.begin(); p != schains.end(); p++) {
 
2448
    for(vector<CHAIN*>::iterator q = chains.begin(); q != chains.end(); q++) {
 
2449
      if (*p == (*q)->name()) {
 
2450
        ECA_LOG_MSG(ECA_LOGGER::system_objects, "Adding chainop to chain " + (*q)->name() + ".");
 
2451
        (*q)->add_chain_operator(cotmp);
 
2452
        (*q)->selected_chain_operator_as_target();
 
2453
        return;
 
2454
      }
 
2455
    }
 
2456
  }
 
2457
}
 
2458
 
 
2459
/**
 
2460
 * If chainsetup has inputs, but no outputs, a default output is
 
2461
 * added.
 
2462
 * 
 
2463
 * @pre is_enabled() != true
 
2464
 */
 
2465
void ECA_CHAINSETUP::add_default_output(void)
 
2466
{
 
2467
  // --------
 
2468
  DBC_REQUIRE(is_enabled() != true);
 
2469
  // --------
 
2470
 
 
2471
  if (inputs.size() > 0 && outputs.size() == 0) {
 
2472
 
 
2473
    // No -o[:] options specified; let's use the default output
 
2474
    
 
2475
    select_all_chains();
 
2476
    interpret_object_option(string("-o:") + ECA_OBJECT_FACTORY::probe_default_output_device());
 
2477
  }
 
2478
}
 
2479
 
 
2480
/**
 
2481
 * If chainsetup has objects that need MIDI services, 
 
2482
 * but no MIDI-devices defined, a default MIDI-device is
 
2483
 * added.
 
2484
 * 
 
2485
 * @pre is_enabled() != true
 
2486
 */
 
2487
void ECA_CHAINSETUP::add_default_midi_device(void)
 
2488
{
 
2489
  if (midi_server_needed_rep == true &&
 
2490
      midi_devices.size() == 0) {
 
2491
    cparser_rep.interpret_object_option("-Md:" + default_midi_device());
 
2492
  }
 
2493
}
 
2494
 
 
2495
/**
 
2496
 * Loads chainsetup options from file.
 
2497
 *
 
2498
 * @pre is_enabled() != true
 
2499
 */
 
2500
void ECA_CHAINSETUP::load_from_file(const string& filename,
 
2501
                                    vector<string>& opts) const throw(ECA_ERROR&) 
 
2502
{
 
2503
  // --------
 
2504
  DBC_REQUIRE(is_enabled() != true);
 
2505
  // --------
 
2506
 
 
2507
  std::ifstream fin (filename.c_str());
 
2508
  if (!fin) throw(ECA_ERROR("ECA_CHAINSETUP", "Couldn't open setup read file: \"" + filename + "\".", ECA_ERROR::retry));
 
2509
 
 
2510
  vector<string> options;
 
2511
  string temp;
 
2512
  while(getline(fin,temp)) {
 
2513
    if (temp.size() > 0 && temp[0] == '#') {
 
2514
      continue;
 
2515
    }
 
2516
    // FIXME: we should add quoting when saving the chainsetup or
 
2517
    // give on quoting altogether...
 
2518
    vector<string> words = kvu_string_to_tokens_quoted(temp);
 
2519
    for(unsigned int n = 0; n < words.size(); n++) {
 
2520
      ECA_LOG_MSG(ECA_LOGGER::system_objects, "Adding \"" + words[n] + "\" to options (loaded from \"" + filename + "\".");
 
2521
      options.push_back(words[n]);
 
2522
    }
 
2523
  }
 
2524
  fin.close();
 
2525
 
 
2526
  opts = COMMAND_LINE::combine(options);
 
2527
}
 
2528
 
 
2529
void ECA_CHAINSETUP::save(void) throw(ECA_ERROR&)
 
2530
 
2531
  if (setup_filename_rep.empty() == true)
 
2532
    setup_filename_rep = setup_name_rep + ".ecs";
 
2533
  save_to_file(setup_filename_rep);
 
2534
}
 
2535
 
 
2536
void ECA_CHAINSETUP::save_to_file(const string& filename) throw(ECA_ERROR&)
 
2537
{
 
2538
  // make sure that all overrides are processed
 
2539
  select_active_buffering_mode();
 
2540
 
 
2541
  std::ofstream fout (filename.c_str());
 
2542
  if (!fout) {
 
2543
    cerr << "Going to throw an exception...\n";
 
2544
    throw(ECA_ERROR("ECA_CHAINSETUP", "Couldn't open setup save file: \"" +
 
2545
                        filename + "\".", ECA_ERROR::retry));
 
2546
  }
 
2547
  else {
 
2548
    fout << "# ecasound chainsetup file" << endl;
 
2549
    fout << endl;
 
2550
 
 
2551
    fout << "# general " << endl;
 
2552
    fout << cparser_rep.general_options_to_string() << endl;
 
2553
    fout << endl;
 
2554
 
 
2555
    string tmpstr = cparser_rep.midi_to_string();
 
2556
    if (tmpstr.size() > 0) {
 
2557
      fout << "# MIDI " << endl;
 
2558
      fout << tmpstr << endl;
 
2559
      fout << endl;      
 
2560
    }
 
2561
 
 
2562
    fout << "# audio inputs " << endl;
 
2563
    fout << cparser_rep.inputs_to_string() << endl;
 
2564
    fout << endl;
 
2565
 
 
2566
    fout << "# audio outputs " << endl;
 
2567
    fout << cparser_rep.outputs_to_string() << endl;
 
2568
    fout << endl;
 
2569
 
 
2570
    tmpstr = cparser_rep.chains_to_string();
 
2571
    if (tmpstr.size() > 0) {
 
2572
      fout << "# chain operators and controllers " << endl;
 
2573
      fout << tmpstr << endl;
 
2574
      fout << endl;      
 
2575
    }
 
2576
 
 
2577
    fout.close();
 
2578
    set_filename(filename);
 
2579
  }
 
2580
}