1 // ------------------------------------------------------------------------
2 // eca-engine.cpp: Main processing engine
3 // Copyright (C) 1999-2009,2012,2015,2020 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 #include <iostream>
25 #include <string>
26 #include <vector>
27 #include <ctime>
28 #include <cmath>
29 #include <utility>
30
31 #include <assert.h>
32 #include <unistd.h>
33 #include <pthread.h>
34 #include <errno.h>
35 #include <sys/time.h> /* gettimeofday() */
36
37 #include <kvu_dbc.h>
38 #include <kvu_numtostr.h>
39 #include <kvu_procedure_timer.h>
40 #include <kvu_rtcaps.h>
41 #include <kvu_threads.h>
42
43 #include "samplebuffer.h"
44 #include "audioio.h"
45 #include "audioio-buffered.h"
46 #include "audioio-device.h"
47 #include "audioio-db-client.h"
48 #include "audioio-loop.h"
49 #include "audioio-barrier.h"
50 #include "audioio-mp3.h"
51 #include "midi-server.h"
52 #include "eca-chain.h"
53 #include "eca-chainop.h"
54 #include "eca-error.h"
55 #include "eca-logger.h"
56 #include "eca-chainsetup-edit.h"
57 #include "eca-engine.h"
58 #include "eca-engine_impl.h"
59
60 using std::cerr;
61 using std::endl;
62 using std::vector;
63
64 /**
65 * Enable and disable features
66 */
67
68 /* Profile callback execution */
69 // #define PROFILE_ENGINE
70
71 /**
72 * Local macro definitions
73 */
74
75 #ifdef PROFILE_ENGINE_EXECUTION
76 #define PROFILE_ENGINE_STATEMENT(x) (x)
77 #else
78 #define PROFILE_ENGINE_STATEMENT(x) ((void)0)
79 #endif
80
81 /**
82 * Prototypes of static functions
83 */
84
85 static void mix_to_outputs_divide_helper(const SAMPLE_BUFFER *from, SAMPLE_BUFFER *to, int divide_by, bool first_time);
86 static void mix_to_outputs_sum_helper(const SAMPLE_BUFFER *from, SAMPLE_BUFFER *to, bool first_time);
87
88 /**
89 * Implementations of non-static functions
90 */
91
92 /**********************************************************************
93 * Driver implementation
94 **********************************************************************/
95
exec(ECA_ENGINE * engine,ECA_CHAINSETUP * csetup)96 int ECA_ENGINE_DEFAULT_DRIVER::exec(ECA_ENGINE* engine, ECA_CHAINSETUP* csetup)
97 {
98 bool drain_at_end = false;
99
100 engine_repp = engine;
101
102 exit_request_rep = false;
103 engine->init_engine_state();
104
105 while(true) {
106
107 engine_repp->check_command_queue();
108
109 /* case 1: external exit request */
110 if (exit_request_rep == true) break;
111
112 /* case 2: engine running, execute one loop iteration */
113 if (engine_repp->status() == ECA_ENGINE::engine_status_running) {
114 engine_repp->engine_iteration();
115 }
116 else {
117 /* case 3a-i: engine finished and in batch mode -> exit */
118 if (engine_repp->status() == ECA_ENGINE::engine_status_finished &&
119 engine_repp->batch_mode() == true) {
120 ECA_LOG_MSG(ECA_LOGGER::system_objects, "batch finished in exec, exit");
121 drain_at_end = true;
122 break;
123 }
124
125 /* case 3a-ii: engine error occured -> exit */
126 else if (engine_repp->status() == ECA_ENGINE::engine_status_error) {
127 ECA_LOG_MSG(ECA_LOGGER::system_objects, "engine error, exit");
128 break;
129 }
130
131 /* case 3b: engine not running, wait for commands */
132 engine_repp->wait_for_commands();
133 }
134
135 engine_repp->update_engine_state();
136 }
137
138 if (engine_repp->is_prepared() == true)
139 engine_repp->stop_operation(drain_at_end);
140
141 return 0;
142 }
143
start(void)144 void ECA_ENGINE_DEFAULT_DRIVER::start(void)
145 {
146 if (engine_repp->is_prepared() != true) engine_repp->prepare_operation();
147 engine_repp->start_operation();
148 }
149
stop(bool drain)150 void ECA_ENGINE_DEFAULT_DRIVER::stop(bool drain)
151 {
152 if (engine_repp->is_prepared() == true) engine_repp->stop_operation(drain);
153 }
154
exit(void)155 void ECA_ENGINE_DEFAULT_DRIVER::exit(void)
156 {
157 if (engine_repp->is_prepared() == true) engine_repp->stop_operation();
158 exit_request_rep = true;
159
160 /* no need to block here as the next
161 * function will be exec()
162 */
163 }
164
165 /**********************************************************************
166 * Engine implementation - Public functions
167 **********************************************************************/
168
169 /**
170 * Context help:
171 * J = originates from driver callback
172 * E = ----- " ------- engine thread (exec())
173 * C = ----- " ------- control thread (external)
174 *
175 * X-level-Y -> Y = steps from originating functions
176 */
177
178 /**
179 * Class constructor. A pointer to an enabled
180 * ECA_CHAINSETUP object must be given as argument.
181 *
182 * @pre csetup != 0
183 * @pre csetup->is_enabled() == true
184 * @post status() == ECA_ENGINE::engine_status_stopped
185 */
ECA_ENGINE(ECA_CHAINSETUP * csetup)186 ECA_ENGINE::ECA_ENGINE(ECA_CHAINSETUP* csetup)
187 : prepared_rep(false),
188 running_rep(false),
189 finished_rep(false),
190 outputs_finished_rep(0),
191 driver_errors_rep(0),
192 csetup_repp(csetup),
193 mixslot_repp(0)
194 {
195 // --
196 DBC_REQUIRE(csetup != 0);
197 DBC_REQUIRE(csetup->is_enabled() == true);
198 // --
199
200 ECA_LOG_MSG(ECA_LOGGER::system_objects, "ECA_ENGINE constructor");
201
202 csetup_repp->toggle_locked_state(true);
203
204 impl_repp = new ECA_ENGINE_impl;
205 mixslot_repp = new SAMPLE_BUFFER(buffersize(), 0);
206
207 init_variables();
208 init_connection_to_chainsetup();
209
210 PROFILE_ENGINE_STATEMENT(init_profiling());
211
212 csetup_repp->toggle_locked_state(false);
213
214 // --
215 DBC_ENSURE(status() == ECA_ENGINE::engine_status_stopped);
216 // --
217 }
218
219 /**
220 * Class destructor.
221 */
~ECA_ENGINE(void)222 ECA_ENGINE::~ECA_ENGINE(void)
223 {
224 ECA_LOG_MSG(ECA_LOGGER::system_objects, "ECA_ENGINE destructor");
225
226 if (csetup_repp != 0) {
227 command(ECA_ENGINE::ep_exit, 0.0f);
228 wait_for_exit(5);
229 if (csetup_repp != 0) {
230 cleanup();
231 }
232 }
233
234 PROFILE_ENGINE_STATEMENT(dump_profile_info());
235
236 if (driver_local == true) {
237 delete driver_repp;
238 driver_repp = 0;
239 }
240
241 for(size_t n = 0; n < cslots_rep.size(); n++) {
242 delete cslots_rep[n];
243 }
244
245 delete mixslot_repp;
246 delete impl_repp;
247
248 ECA_LOG_MSG(ECA_LOGGER::subsystems, "Engine exiting");
249 }
250
251 /**
252 * Launches the engine. This function will block
253 * until processing is finished.
254 *
255 * Note that a exec() is a one-shot function.
256 * It's not possible to call it multiple times.
257 *
258 * @param batch_mode if true, once engine is started
259 * it will continue processing until
260 * 'status() == engine_status_finished'
261 * condition is reached and then exit;
262 * if false, engine will react to
263 * commands until explicit 'exit' is
264 * given
265 *
266 * @see command()
267 * @see status()
268 *
269 * @pre is_valid() == true
270 * @post status() == ECA_ENGINE::engine_status_notready
271 * @post is_valid() != true
272 */
exec(bool batch_mode)273 int ECA_ENGINE::exec(bool batch_mode)
274 {
275 // --
276 DBC_REQUIRE(csetup_repp != 0);
277 DBC_REQUIRE(csetup_repp->is_enabled() == true);
278 // --
279
280 int result = 0;
281
282 csetup_repp->toggle_locked_state(true);
283
284 batchmode_enabled_rep = batch_mode;
285
286 ECA_LOG_MSG(ECA_LOGGER::subsystems, "Engine - Driver start");
287
288 int res = driver_repp->exec(this, csetup_repp);
289 if (res < 0) {
290 ++driver_errors_rep;
291 ECA_LOG_MSG(ECA_LOGGER::info,
292 "WARNING: Engine has raised an error! "
293 "Possible causes: connection lost to system services, unable to adapt "
294 "to changes in operating environment, etc.");
295 }
296
297 csetup_repp->toggle_locked_state(false);
298
299 signal_exit();
300
301 if (outputs_finished_rep > 0) {
302 ECA_LOG_MSG(ECA_LOGGER::info, "WARNING: An output object has raised an error! "
303 "Possible causes: Out of disk space, permission denied, unable to launch external "
304 "applications needed in processing, etc.");
305 }
306
307 DBC_CHECK(status() == ECA_ENGINE::engine_status_stopped ||
308 status() == ECA_ENGINE::engine_status_finished ||
309 status() == ECA_ENGINE::engine_status_error);
310
311 if (status() == ECA_ENGINE::engine_status_error) {
312 result = -1;
313 }
314
315 cleanup();
316
317 ECA_LOG_MSG(ECA_LOGGER::user_objects,
318 "Engine state when finishing: " +
319 kvu_numtostr(static_cast<int>(status())));
320
321 // --
322 DBC_ENSURE(status() == ECA_ENGINE::engine_status_notready);
323 // --
324
325 return result;
326 }
327
328 /**
329 * Sends 'cmd' to engines command queue. Commands are
330 * processed in the server's main loop.
331 *
332 * context: C-level-0
333 * must no be called from exec() context
334 */
command(Engine_command_t cmd,double arg)335 void ECA_ENGINE::command(Engine_command_t cmd, double arg)
336 {
337 ECA_ENGINE::complex_command_t item;
338 item.type = cmd;
339 item.m.legacy.value = arg;
340 impl_repp->command_queue_rep.push_back(item);
341 }
342
343 /**
344 * Sends 'ccmd' to engines command queue. Commands are
345 * processed in the server's main loop. Passing a complex
346 * command allows to address objects regardless of
347 * the state of ECA_CHAINSETUP iterators (i.e. currently
348 * selected objects).
349 *
350 * context: C-level-0
351 * must no be called from exec() context
352 */
command(complex_command_t ccmd)353 void ECA_ENGINE::command(complex_command_t ccmd)
354 {
355 impl_repp->command_queue_rep.push_back(ccmd);
356 }
357
358 /**
359 * Wait for a stop signal. Functions blocks until
360 * the signal is received or 'timeout' seconds
361 * has elapsed.
362 *
363 * context: C-level-0
364 * must not be run from the engine
365 * driver context
366 *
367 * @see signal_stop()
368 */
wait_for_stop(int timeout)369 void ECA_ENGINE::wait_for_stop(int timeout)
370 {
371 struct timespec timeoutspec;
372
373 // FIXME: start to use MONOTONIC, needs pthread_condattr_setclock
374 int ret = kvu_pthread_cond_timeout(timeout, &timeoutspec, false);
375 DBC_CHECK(ret == 0);
376
377 pthread_mutex_lock(&impl_repp->ecasound_stop_mutex_repp);
378 while(running_rep == true) {
379 ret = pthread_cond_timedwait(&impl_repp->ecasound_stop_cond_repp,
380 &impl_repp->ecasound_stop_mutex_repp,
381 &timeoutspec);
382 ECA_LOG_MSG(ECA_LOGGER::system_objects,
383 kvu_pthread_timed_wait_result(ret, "wait_for_stop"));
384 }
385 pthread_mutex_unlock(&impl_repp->ecasound_stop_mutex_repp);
386 }
387
388 /**
389 * Wait for an exit signal. Function blocks until
390 * the signal is received or 'timeout' seconds
391 * has elapsed.
392 *
393 * context: C-level-0
394 *
395 * @see signal_exit()
396 */
wait_for_exit(int timeout)397 void ECA_ENGINE::wait_for_exit(int timeout)
398 {
399
400 int ret = kvu_pthread_timed_wait(&impl_repp->ecasound_exit_mutex_repp,
401 &impl_repp->ecasound_exit_cond_repp,
402 timeout);
403 ECA_LOG_MSG(ECA_LOGGER::info,
404 kvu_pthread_timed_wait_result(ret, "(eca_main) wait_for_exit"));
405 }
406
407 /**********************************************************************
408 * Engine implementation - Public functions for observing engine
409 * status information
410 **********************************************************************/
411
412 /**
413 * Returns true engine's internal
414 * state is valid for processing.
415 *
416 * context: C-level-0
417 * no limitations
418 */
is_valid(void) const419 bool ECA_ENGINE::is_valid(void) const
420 {
421 if (csetup_repp == 0 ||
422 csetup_repp->is_enabled() != true ||
423 csetup_repp->is_valid() != true ||
424 chains_repp == 0 ||
425 chains_repp->size() == 0 ||
426 inputs_repp == 0 ||
427 inputs_repp->size() == 0 ||
428 outputs_repp == 0 ||
429 outputs_repp->size() == 0) {
430
431 return false;
432 }
433
434 return true;
435 }
436
437 /**
438 * Whether current setup has finite length.
439 *
440 * context: C-level-0
441 */
is_finite_length(void) const442 bool ECA_ENGINE::is_finite_length(void) const
443 {
444 DBC_CHECK(csetup_repp != 0);
445
446 if (csetup_repp->max_length_set() == true ||
447 csetup_repp->number_of_realtime_inputs() == 0) {
448 return true;
449 }
450
451 return false;
452 }
453
454 /**
455 * Returns engine's current status.
456 *
457 * context: C-level-0
458 * no limitations
459 */
status(void) const460 ECA_ENGINE::Engine_status_t ECA_ENGINE::status(void) const
461 {
462 if (csetup_repp == 0)
463 return ECA_ENGINE::engine_status_notready;
464
465 /* calculated in update_engine_status() */
466 if (finished_rep == true)
467 return ECA_ENGINE::engine_status_finished;
468
469 if (outputs_finished_rep > 0 ||
470 driver_errors_rep > 0)
471 return ECA_ENGINE::engine_status_error;
472
473 if (is_running() == true)
474 return ECA_ENGINE::engine_status_running;
475
476 if (is_prepared() == true)
477 return ECA_ENGINE::engine_status_stopped;
478
479 return ECA_ENGINE::engine_status_stopped;
480 }
481
482 /**********************************************************************
483 * Engine implementation - API for engine driver objects
484 **********************************************************************/
485
486 /**
487 * Processes available new commands. If no
488 * messages are available, function will return
489 * immediately without blocking.
490 *
491 * context: E-level-1
492 * can be run at the same time as engine_iteration();
493 * note! this is called with the engine lock held
494 * so no long operations allowed!
495 */
check_command_queue(void)496 void ECA_ENGINE::check_command_queue(void)
497 {
498 while(impl_repp->command_queue_rep.is_empty() != true) {
499 ECA_ENGINE::complex_command_t item;
500 int popres = impl_repp->command_queue_rep.pop_front(&item);
501
502 if (popres <= 0) {
503 /* queue is empty or temporarily unavailable, unable to continue
504 * processing messages without blocking */
505 break;
506 }
507
508 switch(item.type)
509 {
510 // ---
511 // Basic commands.
512 // ---
513 case ep_exit:
514 {
515 // FIXME: is clear the right thing or should remaining cmds
516 // be still processed? OTOH, client app should know...
517 impl_repp->command_queue_rep.clear();
518 ECA_LOG_MSG(ECA_LOGGER::system_objects,"ecasound_queue: exit!");
519 driver_repp->exit();
520 return;
521 }
522
523 // ---
524 // Chain operators (stateless addressing)
525 // ---
526 case ep_exec_edit:
527 {
528 csetup_repp->execute_edit(item.cs);
529 if (item.cs.need_chain_reinit) {
530 reinit_chains(true);
531 }
532 break;
533 }
534 case ep_prepare:
535 {
536 if (is_prepared() != true)
537 prepare_operation();
538 break;
539 }
540 case ep_start:
541 {
542 if (status() != engine_status_running)
543 request_start();
544 break;
545 }
546 case ep_stop:
547 {
548 if (status() == engine_status_running ||
549 status() == engine_status_finished) request_stop(false);
550 break;
551 }
552 case ep_stop_with_drain:
553 {
554 if (status() == engine_status_running ||
555 status() == engine_status_finished)
556 request_stop(true);
557 break;
558 }
559
560 // ---
561 // Global position
562 // ---
563 case ep_rewind: { change_position(- item.m.legacy.value); break; }
564 case ep_forward: { change_position(item.m.legacy.value); break; }
565 case ep_setpos: { set_position(item.m.legacy.value); break; }
566 case ep_setpos_samples: { set_position_samples(static_cast<SAMPLE_SPECS::sample_pos_t>(item.m.legacy.value)); break; }
567 case ep_setpos_live_samples: { set_position_samples_live(static_cast<SAMPLE_SPECS::sample_pos_t>(item.m.legacy.value)); break; }
568
569 case ep_debug: break;
570
571 } /* switch */
572
573 }
574 }
575
576 /**
577 * Waits for new commands to arrive. Function
578 * will block until at least one new message
579 * is available or until a timeout occurs.
580 *
581 * context: E-level-1
582 * can be run at the same time as
583 * engine_iteration()
584 */
wait_for_commands(void)585 void ECA_ENGINE::wait_for_commands(void)
586 {
587 impl_repp->command_queue_rep.poll(5, 0);
588 }
589
590 /**
591 * Intializes internal state variables.
592 *
593 * context: E-level-1
594 * must not be run at the same
595 * time as engine_iteration()
596 *
597 * @see update_engine_state()
598 */
init_engine_state(void)599 void ECA_ENGINE::init_engine_state(void)
600 {
601 finished_rep = false;
602 inputs_not_finished_rep = 1; // for the 1st iteration
603 outputs_finished_rep = 0;
604 mixslot_repp->event_tag_set(SAMPLE_BUFFER::tag_end_of_stream, false);
605 for(size_t n = 0; n < cslots_rep.size(); n++) {
606 cslots_rep[n]->event_tag_set(SAMPLE_BUFFER::tag_end_of_stream, false);
607 }
608 }
609
610 /**
611 * Updates engine state to match current
612 * situation.
613 *
614 * context: J-level-0
615 * must not be run at the same
616 * time as engine_iteration()
617 *
618 * @see init_engine_state()
619 */
update_engine_state(void)620 void ECA_ENGINE::update_engine_state(void)
621 {
622 // --
623 // Check whether all inputs have finished
624 // (note: as update_engine_state() is
625 // guaranteed to not to be called at the same
626 // time as engine_iteration(), this is the
627 // only safe place to calculate finished state
628
629 if (inputs_not_finished_rep == 0 &&
630 outputs_finished_rep == 0 &&
631 finished_rep != true) {
632 if (is_running() == true) {
633 ECA_LOG_MSG(ECA_LOGGER::system_objects,"all inputs finished - stop");
634 // FIXME: this is still wrong, command() is not fully rt-safe
635 // we are not allowed to call request_stop here
636 command(ECA_ENGINE::ep_stop_with_drain, 0.0f);
637 }
638
639 state_change_to_finished();
640 }
641
642 // --
643 // Check whether some output has raised an error
644
645 if (status() == ECA_ENGINE::engine_status_error) {
646 if (is_running() == true) {
647 ECA_LOG_MSG(ECA_LOGGER::system_objects,"output error - stop");
648 // FIXME: this is still wrong, command() is not fully rt-safe
649 // we are not allowed to call request_stop here
650 command(ECA_ENGINE::ep_stop, 0.0f);
651 }
652 }
653 }
654
655 /**
656 * Executes one engine loop iteration. It is critical
657 * that this function is only called when engine is
658 * running.
659 *
660 * @pre is_running() == true
661 *
662 * context: J-level-0
663 */
engine_iteration(void)664 void ECA_ENGINE::engine_iteration(void)
665 {
666 DBC_CHECK(is_running() == true);
667
668 PROFILE_ENGINE_STATEMENT(impl_repp->looptimer_rep.start(); impl_repp->looptimer_range_rep.start());
669
670 inputs_not_finished_rep = 0;
671 prehandle_control_position();
672 inputs_to_chains();
673 process_chains();
674 // FIXME: add support for sub-buffersize offsets
675 if (preroll_samples_rep >= recording_offset_rep) {
676 /* record material to non-real-time outputs */
677 mix_to_outputs(false);
678 }
679 else {
680 /* skip slave targets */
681 mix_to_outputs(true);
682 preroll_samples_rep += buffersize();
683 }
684 posthandle_control_position();
685
686 PROFILE_ENGINE_STATEMENT(impl_repp->looptimer_rep.stop(); impl_repp->looptimer_range_rep.stop());
687 }
688
689 /**
690 * Reinitialize chains
691 *
692 * Flush any existing state from the chain operators (e.g.
693 * old audio data in buffers, changes in configuration, and
694 * so forth).
695 *
696 * @arg force force reinitialization even if chain itself
697 * reports it is properly initialized
698 */
reinit_chains(bool force)699 void ECA_ENGINE::reinit_chains(bool force)
700 {
701 for(size_t i = 0; i != chains_repp->size(); i++) {
702 if (force == true ||
703 (*chains_repp)[i]->is_initialized() != true) {
704 (*chains_repp)[i]->init(0, 0, 0);
705 }
706 }
707 }
708
709 /**
710 * Prepares engine for operation. Prepares all
711 * realtime devices and starts servers.
712 *
713 * This function should be called by the
714 * driver before it starts iterating the
715 * engine's main loop.
716 *
717 * context: E-level-1/3
718 * must not be run at the same time
719 * as engine_iteration()
720 *
721 * @pre is_running() != true
722 * @pre is_prepared() != true
723 * @post is_prepared() == true
724 * @post status() == ECA_ENGINE::engine_status_running
725 */
prepare_operation(void)726 void ECA_ENGINE::prepare_operation(void)
727 {
728 // ---
729 DBC_REQUIRE(is_running() != true);
730 DBC_REQUIRE(is_prepared() != true);
731 // ---
732
733 /* 1. acquire rt-lock for chainsetup and samplebuffers */
734 csetup_repp->toggle_locked_state(true);
735
736 for(size_t n = 0; n < cslots_rep.size(); n++) {
737 cslots_rep[n]->set_rt_lock(true);
738 }
739 mixslot_repp->set_rt_lock(true);
740
741 /* 2. reinitialize chains if necessary */
742 reinit_chains(true);
743
744 /* 3. start subsystem servers and forked audio objects */
745 start_forked_objects();
746 start_servers();
747
748 /* 4. prepare rt objects */
749 prepare_realtime_objects();
750
751 /* ... initial offset is needed because preroll is
752 * incremented only after checking whether we are
753 * still in preroll mode */
754 preroll_samples_rep = buffersize();
755
756 /* 6. enable rt-scheduling */
757 if (csetup_repp->raised_priority() == true) {
758 if (kvu_set_thread_scheduling(SCHED_FIFO, csetup_repp->get_sched_priority()) != 0)
759 ECA_LOG_MSG(ECA_LOGGER::system_objects, "Unable to change scheduling policy!");
760 else
761 ECA_LOG_MSG(ECA_LOGGER::user_objects,
762 std::string("Using realtime-scheduling (SCHED_FIFO:")
763 + kvu_numtostr(csetup_repp->get_sched_priority()) + ").");
764 }
765
766 /* 7. change engine to active and running */
767 prepared_rep = true;
768 init_engine_state();
769 ECA_LOG_MSG(ECA_LOGGER::system_objects, "engine prepared");
770
771 // ---
772 DBC_ENSURE(is_prepared() == true);
773 DBC_ENSURE(status() == ECA_ENGINE::engine_status_stopped);
774 // ---
775 }
776
777 /**
778 * Starts engine operation.
779 *
780 * This function should be called by the
781 * driver just before it starts iterating the
782 * engine's main loop.
783 *
784 * context: E-level-1/3
785 * must not be run at the same time
786 * as engine_iteration()
787 *
788 * @pre is_prepared() == true
789 * @pre is_running() != true
790 * @post is_running() == true
791 * @post status() == ECA_ENGINE::engine_status_running
792 */
start_operation(void)793 void ECA_ENGINE::start_operation(void)
794 {
795 // ---
796 DBC_REQUIRE(is_prepared() == true);
797 DBC_REQUIRE(is_running() != true);
798 // ---
799
800 ECA_LOG_MSG(ECA_LOGGER::system_objects, "starting engine operation!");
801
802 start_realtime_objects();
803 running_rep = true;
804
805 // ---
806 DBC_ENSURE(is_running() == true);
807 DBC_ENSURE(status() == ECA_ENGINE::engine_status_running);
808 // ---
809 }
810
811 /**
812 * Stops all realtime devices and servers.
813 *
814 * This function should be called by the
815 * driver when it stops iterating the
816 * engine's main loop.
817 *
818 * context: E-level-1/3
819 * must not be run at the same time
820 * as engine_iteration()
821 *
822 * @param drain whether to block until all queued data is processed
823 * by realtime devices before stopping
824 *
825 * @pre is_running() == true
826 * @post is_running() != true
827 * @post is_prepared() != true
828 */
stop_operation(bool drain)829 void ECA_ENGINE::stop_operation(bool drain)
830 {
831 // ---
832 DBC_REQUIRE(is_prepared() == true);
833 // ---
834
835 ECA_LOG_MSG(ECA_LOGGER::system_objects, "stopping engine operation!");
836
837 /* stop realtime devices */
838 for (unsigned int adev_sizet = 0; adev_sizet != realtime_objects_rep.size(); adev_sizet++) {
839 if (realtime_objects_rep[adev_sizet]->is_running() == true)
840 realtime_objects_rep[adev_sizet]->stop(drain);
841 }
842
843 prepared_rep = false;
844
845 /* release samplebuffer rt-locks */
846 for(size_t n = 0; n < cslots_rep.size(); n++) {
847 cslots_rep[n]->set_rt_lock(false);
848 }
849 mixslot_repp->set_rt_lock(false);
850
851 stop_servers();
852 stop_forked_objects();
853
854 /* lower priority back to normal */
855 if (csetup_repp->raised_priority() == true) {
856 if (kvu_set_thread_scheduling(SCHED_OTHER, 0) != 0)
857 ECA_LOG_MSG(ECA_LOGGER::info, "Unable to change scheduling back to SCHED_OTHER!");
858 else
859 ECA_LOG_MSG(ECA_LOGGER::system_objects, "Changed back to non-realtime scheduling SCHED_OTHER.");
860 }
861
862 /* release chainsetup lock */
863 csetup_repp->toggle_locked_state(false);
864
865 /* signals wait_for_stop() that engine operation has stopped */
866 signal_stop();
867
868 // ---
869 DBC_ENSURE(is_running() != true);
870 DBC_ENSURE(is_prepared() != true);
871 // ---
872 }
873
874 /**
875 * Whether engine has been actived
876 * with prepare_operation().
877 *
878 * context: no limitations
879 */
is_prepared(void) const880 bool ECA_ENGINE::is_prepared(void) const
881 {
882 return prepared_rep;
883 }
884
885 /**
886 * Whether engine has been started
887 * with start_operation().
888 *
889 * context: no limitations
890 */
is_running(void) const891 bool ECA_ENGINE::is_running(void) const
892 {
893 return running_rep;
894 }
895
896 /**********************************************************************
897 * Engine implementation - Attribute functions
898 **********************************************************************/
899
buffersize(void) const900 long int ECA_ENGINE::buffersize(void) const
901 {
902 DBC_CHECK(csetup_repp != 0);
903 return csetup_repp->buffersize();
904 }
905
max_channels(void) const906 int ECA_ENGINE::max_channels(void) const
907 {
908 int result = 0;
909 for(unsigned int n = 0; n < csetup_repp->inputs.size(); n++) {
910 if (csetup_repp->inputs[n]->channels() > result)
911 result = csetup_repp->inputs[n]->channels();
912 }
913 for(unsigned int n = 0; n < csetup_repp->outputs.size(); n++) {
914 if (csetup_repp->outputs[n]->channels() > result)
915 result = csetup_repp->outputs[n]->channels();
916 }
917 return result;
918 }
919
920 /**********************************************************************
921 * Engine implementation - Private functions for transport control
922 **********************************************************************/
923
924 /**
925 * Requests the engine driver to start operation.
926 *
927 * This function should only be called from
928 * check_command_queue().
929 *
930 * @pre status() != engine_status_running
931 *
932 * context: E-level-2
933 */
request_start(void)934 void ECA_ENGINE::request_start(void)
935 {
936 // ---
937 DBC_REQUIRE(status() != engine_status_running);
938 // ---
939
940 ECA_LOG_MSG(ECA_LOGGER::user_objects, "Request start");
941
942 // --
943 // start the driver
944 driver_repp->start();
945 }
946
947 /**
948 * Requests the engine driver to stop operation.
949 *
950 * This function should only be called from
951 * check_command_queue().
952 *
953 * @pre status() == ECA_ENGINE::engine_status_running ||
954 * status() == ECA_ENGINE::engine_status_finished
955 *
956 * context: E-level-2
957 */
request_stop(bool drain)958 void ECA_ENGINE::request_stop(bool drain)
959 {
960 // ---
961 DBC_REQUIRE(status() == engine_status_running ||
962 status() == engine_status_finished);
963 // ---
964
965 ECA_LOG_MSG(ECA_LOGGER::user_objects,
966 std::string("Request stop (") +
967 (drain ? std::string("drain") : std::string("no-drain")) + ")");
968
969 driver_repp->stop(drain);
970 }
971
972 /**
973 * Sends a stop signal indicating that engine
974 * state has changed to stopped.
975 *
976 * context: E-level-1/4
977 *
978 * @see wait_for_stop()
979 */
signal_stop(void)980 void ECA_ENGINE::signal_stop(void)
981 {
982 pthread_mutex_lock(&impl_repp->ecasound_stop_mutex_repp);
983 ECA_LOG_MSG(ECA_LOGGER::system_objects, "Signaling stop");
984 running_rep = false;
985 pthread_cond_broadcast(&impl_repp->ecasound_stop_cond_repp);
986 pthread_mutex_unlock(&impl_repp->ecasound_stop_mutex_repp);
987 }
988
989 /**
990 * Sends an exit signal indicating that engine
991 * driver has exited.
992 *
993 * context: E-level-1/4
994 *
995 * @see wait_for_exit()
996 */
signal_exit(void)997 void ECA_ENGINE::signal_exit(void)
998 {
999 pthread_mutex_lock(&impl_repp->ecasound_exit_mutex_repp);
1000 ECA_LOG_MSG(ECA_LOGGER::system_objects, "Signaling exit");
1001 pthread_cond_broadcast(&impl_repp->ecasound_exit_cond_repp);
1002 pthread_mutex_unlock(&impl_repp->ecasound_exit_mutex_repp);
1003 }
1004
1005 /**
1006 * Processing is start If and only if processing
1007 * previously stopped with conditional_stop().
1008 *
1009 * context: E-level-3
1010 */
conditional_start(void)1011 void ECA_ENGINE::conditional_start(void)
1012 {
1013 if (was_running_rep == true) {
1014 // don't call request_start(), as it would signal that we are
1015 // starting from completely halted state
1016 if (is_prepared() != true) prepare_operation();
1017 start_operation();
1018 }
1019 }
1020
1021 /**
1022 * Processing is stopped.
1023 *
1024 * context: E-level-3
1025 *
1026 * @see conditional_stop()
1027 * @see request_stop()
1028 */
conditional_stop(void)1029 void ECA_ENGINE::conditional_stop(void)
1030 {
1031 if (status() == ECA_ENGINE::engine_status_running) {
1032 ECA_LOG_MSG(ECA_LOGGER::system_objects,"conditional stop");
1033 was_running_rep = true;
1034 // don't call request_stop(), as it would signal that we are
1035 // stopping completely (JACK transport stop will be sent to all)
1036 if (is_prepared() == true) stop_operation(false);
1037 }
1038 else was_running_rep = false;
1039 }
1040
start_servers(void)1041 void ECA_ENGINE::start_servers(void)
1042 {
1043 if (csetup_repp->double_buffering() == true) {
1044 csetup_repp->pserver_repp->start();
1045 ECA_LOG_MSG(ECA_LOGGER::user_objects, "prefilling i/o buffers.");
1046 csetup_repp->pserver_repp->wait_for_full();
1047 ECA_LOG_MSG(ECA_LOGGER::user_objects, "i/o buffers prefilled.");
1048 }
1049
1050 if (use_midi_rep == true) {
1051 csetup_repp->midi_server_repp->start();
1052 }
1053 }
1054
stop_servers(void)1055 void ECA_ENGINE::stop_servers(void)
1056 {
1057 if (csetup_repp->double_buffering() == true) {
1058 csetup_repp->pserver_repp->stop();
1059 csetup_repp->pserver_repp->wait_for_stop();
1060 }
1061
1062 if (use_midi_rep == true) {
1063 csetup_repp->midi_server_repp->stop();
1064 }
1065 }
1066
1067 /**
1068 * Goes through all input/outputs in 'vec', checks whether they
1069 * implement the AUDIO_IO_BARRIER interface, and if yes,
1070 * issues either 'start_io()' or 'stop_io()' on them.
1071 */
priv_toggle_forked_objects(bool start,std::vector<AUDIO_IO * > * vec)1072 static void priv_toggle_forked_objects(bool start, std::vector<AUDIO_IO*>* vec)
1073 {
1074 unsigned int n;
1075 for(n = 0; n < vec->size(); n++) {
1076 AUDIO_IO_BARRIER *barrier
1077 = dynamic_cast<AUDIO_IO_BARRIER*>((*vec)[n]);
1078
1079 if (barrier) {
1080 if (start)
1081 barrier->start_io();
1082 else
1083 barrier->stop_io();
1084 }
1085 }
1086 }
1087
start_forked_objects(void)1088 void ECA_ENGINE::start_forked_objects(void)
1089 {
1090 priv_toggle_forked_objects(true, inputs_repp);
1091 priv_toggle_forked_objects(true, outputs_repp);
1092 }
1093
stop_forked_objects(void)1094 void ECA_ENGINE::stop_forked_objects(void)
1095 {
1096 priv_toggle_forked_objects(false, inputs_repp);
1097 priv_toggle_forked_objects(false, outputs_repp);
1098 }
1099
state_change_to_finished(void)1100 void ECA_ENGINE::state_change_to_finished(void)
1101 {
1102 if (finished_rep != true) {
1103 ECA_LOG_MSG_NOPREFIX(ECA_LOGGER::info, "");
1104 ECA_LOG_MSG(ECA_LOGGER::subsystems, "Engine - Processing finished");
1105 }
1106 finished_rep = true;
1107 }
1108
prepare_realtime_objects(void)1109 void ECA_ENGINE::prepare_realtime_objects(void)
1110 {
1111 /* 1. prepare objects */
1112 for (unsigned int n = 0; n < realtime_objects_rep.size(); n++) {
1113 realtime_objects_rep[n]->prepare();
1114 }
1115
1116 /* 2. prefill rt output objects with silence */
1117 mixslot_repp->make_silent();
1118 for (unsigned int n = 0; n < realtime_outputs_rep.size(); n++) {
1119 if (realtime_outputs_rep[n]->prefill_space() > 0) {
1120 if (realtime_outputs_rep[n]->prefill_space() <
1121 prefill_threshold_rep * buffersize()) {
1122
1123 ECA_LOG_MSG(ECA_LOGGER::user_objects,
1124 "audio output '" +
1125 realtime_outputs_rep[n]->name() +
1126 "' only offers " +
1127 kvu_numtostr(realtime_outputs_rep[n]->prefill_space()) +
1128 " frames of prefill space. Decreasing amount of prefill.");
1129
1130 prefill_threshold_rep = realtime_outputs_rep[n]->prefill_space() / buffersize();
1131 }
1132
1133 ECA_LOG_MSG(ECA_LOGGER::user_objects,
1134 "prefilling rt-outputs with " +
1135 kvu_numtostr(prefill_threshold_rep) +
1136 " blocks.");
1137
1138 for (int m = 0; m < prefill_threshold_rep; m++) {
1139 realtime_outputs_rep[n]->write_buffer(mixslot_repp);
1140 }
1141 }
1142 }
1143 }
1144
start_realtime_objects(void)1145 void ECA_ENGINE::start_realtime_objects(void)
1146 {
1147 /* 1. start all realtime devices */
1148 for (unsigned int n = 0; n < realtime_objects_rep.size(); n++)
1149 realtime_objects_rep[n]->start();
1150 }
1151
1152 /**
1153 * Performs a close-open cycle for all realtime
1154 * devices.
1155 */
reset_realtime_devices(void)1156 void ECA_ENGINE::reset_realtime_devices(void)
1157 {
1158 for (size_t n = 0; n < realtime_objects_rep.size(); n++) {
1159 if (realtime_objects_rep[n]->is_open() == true) {
1160 ECA_LOG_MSG(ECA_LOGGER::user_objects,
1161 "Reseting rt-object " +
1162 realtime_objects_rep[n]->label());
1163 realtime_objects_rep[n]->close();
1164 }
1165 }
1166 for (size_t n = 0; n < realtime_objects_rep.size(); n++) {
1167 realtime_objects_rep[n]->open();
1168 }
1169 }
1170
1171 /**********************************************************************
1172 * Engine implementation - Private functions for observing and
1173 * modifying position
1174 **********************************************************************/
1175
current_position_in_samples(void) const1176 SAMPLE_SPECS::sample_pos_t ECA_ENGINE::current_position_in_samples(void) const
1177 {
1178 return csetup_repp->position_in_samples();
1179 }
1180
current_position_in_seconds_exact(void) const1181 double ECA_ENGINE::current_position_in_seconds_exact(void) const
1182 {
1183 return csetup_repp->position_in_seconds_exact();
1184 }
1185
1186 // FIXME: remove
1187 #if 0
1188 double ECA_ENGINE::current_position_chain(void) const
1189 {
1190 AUDIO_IO* ptr = (*inputs_repp)[(*chains_repp)[csetup_repp->active_chain_index_rep]->connected_input()];
1191 return ptr->position_in_seconds_exact();
1192 return 0.0f;
1193 }
1194 #endif
1195
1196 /**
1197 * Seeks to position 'seconds'. Affects all input and
1198 * outputs objects, and the chainsetup object position.
1199 *
1200 * context: E-level-2
1201 */
set_position(double seconds)1202 void ECA_ENGINE::set_position(double seconds)
1203 {
1204 conditional_stop();
1205 csetup_repp->seek_position_in_seconds(seconds);
1206 // reinit chains to flush out any stale audio data related
1207 // to the old position
1208 reinit_chains(true);
1209 // FIXME: calling init_engine_state() may lead to races
1210 init_engine_state();
1211 conditional_start();
1212 }
1213
1214 /**
1215 * Seeks to position 'samples'. Affects all input and
1216 * outputs objects, and the chainsetup object position.
1217 *
1218 * context: E-level-2
1219 */
set_position_samples(SAMPLE_SPECS::sample_pos_t samples)1220 void ECA_ENGINE::set_position_samples(SAMPLE_SPECS::sample_pos_t samples)
1221 {
1222 conditional_stop();
1223 csetup_repp->seek_position_in_samples(samples);
1224 // reinit chains to flush out any stale audio data related
1225 // to the old position
1226 reinit_chains(true);
1227 // FIXME: calling init_engine_state() may lead to races
1228 init_engine_state();
1229 conditional_start();
1230 }
1231
1232 /**
1233 * Seeks to position 'samples' without stopping the engine.
1234 * Affects all input and outputs objects, and the chainsetup
1235 * object position.
1236 *
1237 * context: E-level-2
1238 */
set_position_samples_live(SAMPLE_SPECS::sample_pos_t samples)1239 void ECA_ENGINE::set_position_samples_live(SAMPLE_SPECS::sample_pos_t samples)
1240 {
1241 csetup_repp->seek_position_in_samples(samples);
1242 // FIXME: calling init_engine_state() may lead to races
1243 init_engine_state();
1244 }
1245
1246 /**
1247 * Seeks to position 'current+seconds'. Affects all input and
1248 * outputs objects, and the chainsetup object position.
1249 *
1250 * context: E-level-2
1251 */
change_position(double seconds)1252 void ECA_ENGINE::change_position(double seconds)
1253 {
1254 double curpos = csetup_repp->position_in_seconds_exact();
1255 conditional_stop();
1256 csetup_repp->seek_position_in_seconds(curpos + seconds);
1257 conditional_start();
1258 }
1259
1260 /**
1261 * Calculates how much data we need to process and sets the
1262 * buffersize accordingly for all non-real-time inputs.
1263 *
1264 * context: J-level-1
1265 */
prehandle_control_position(void)1266 void ECA_ENGINE::prehandle_control_position(void)
1267 {
1268 csetup_repp->change_position_in_samples(buffersize());
1269 if (csetup_repp->max_length_set() == true &&
1270 csetup_repp->is_over_max_length() == true) {
1271 int extra_tail = csetup_repp->position_in_samples() -
1272 csetup_repp->max_length_in_samples();
1273 int buffer_remain = buffersize() - extra_tail;
1274 if (buffer_remain < 0)
1275 buffer_remain = 0;
1276 else if (buffer_remain > buffersize())
1277 buffer_remain = buffersize();
1278 for(unsigned int adev_sizet = 0; adev_sizet < non_realtime_inputs_rep.size(); adev_sizet++) {
1279 non_realtime_inputs_rep[adev_sizet]->set_buffersize(buffer_remain);
1280 }
1281 }
1282 }
1283
1284 /**
1285 * If we've processed all the data that was requested, stop or rewind.
1286 * Also resets buffersize to its default value. If finished
1287 * state is reached, engine status is set to
1288 * 'ECA_ENGINE::engine_status_finished'.
1289 */
posthandle_control_position(void)1290 void ECA_ENGINE::posthandle_control_position(void)
1291 {
1292 if (csetup_repp->max_length_set() == true &&
1293 csetup_repp->is_over_max_length() == true) {
1294 if (csetup_repp->looping_enabled() == true) {
1295 ECA_LOG_MSG(ECA_LOGGER::system_objects,"loop point reached");
1296 inputs_not_finished_rep = 1;
1297 csetup_repp->seek_position_in_samples(0);
1298 for(unsigned int adev_sizet = 0; adev_sizet < non_realtime_inputs_rep.size(); adev_sizet++) {
1299 non_realtime_inputs_rep[adev_sizet]->set_buffersize(buffersize());
1300 }
1301 }
1302 else {
1303 ECA_LOG_MSG(ECA_LOGGER::system_objects,"posthandle_c_p over_max - stop");
1304 if (status() == ECA_ENGINE::engine_status_running ||
1305 status() == ECA_ENGINE::engine_status_finished) {
1306 command(ECA_ENGINE::ep_stop_with_drain, 0.0f);
1307 }
1308 state_change_to_finished();
1309 }
1310 }
1311 }
1312
1313 /**********************************************************************
1314 * Engine implementation - Private functions for setup and cleanup
1315 **********************************************************************/
1316
1317 /**
1318 * Called only from class constructor.
1319 */
init_variables(void)1320 void ECA_ENGINE::init_variables(void)
1321 {
1322 use_midi_rep = false;
1323 batchmode_enabled_rep = false;
1324 driver_local = false;
1325
1326 pthread_cond_init(&impl_repp->ecasound_stop_cond_repp, NULL);
1327 pthread_mutex_init(&impl_repp->ecasound_stop_mutex_repp, NULL);
1328 pthread_cond_init(&impl_repp->ecasound_exit_cond_repp, NULL);
1329 pthread_mutex_init(&impl_repp->ecasound_exit_mutex_repp, NULL);
1330 }
1331
1332 /**
1333 * Called only from class constructor.
1334 */
init_connection_to_chainsetup(void)1335 void ECA_ENGINE::init_connection_to_chainsetup(void)
1336 {
1337 inputs_repp = &(csetup_repp->inputs);
1338 outputs_repp = &(csetup_repp->outputs);
1339 chains_repp = &(csetup_repp->chains);
1340
1341 init_engine_state();
1342 init_driver();
1343 init_prefill();
1344 init_servers();
1345 init_chains();
1346 create_cache_object_lists();
1347 update_cache_chain_connections();
1348 update_cache_latency_values();
1349 }
1350
1351 /**
1352 * Initializes the engine driver object.
1353 */
init_driver(void)1354 void ECA_ENGINE::init_driver(void)
1355 {
1356 if (csetup_repp->engine_driver_repp != 0) {
1357 driver_repp = csetup_repp->engine_driver_repp;
1358 driver_local = false;
1359 }
1360 else {
1361 driver_repp = new ECA_ENGINE_DEFAULT_DRIVER();
1362 driver_local = true;
1363 }
1364 }
1365
1366 /**
1367 * Initializes prefill variables.
1368 */
init_prefill(void)1369 void ECA_ENGINE::init_prefill(void)
1370 {
1371 int channels = (max_channels() > 0 ? max_channels() : 1);
1372 prefill_threshold_rep = 0;
1373
1374 if (csetup_repp->max_buffers() == true)
1375 prefill_threshold_rep = ECA_ENGINE::prefill_threshold_constant / buffersize() / channels;
1376
1377 if (prefill_threshold_rep < ECA_ENGINE::prefill_blocks_constant)
1378 prefill_threshold_rep = ECA_ENGINE::prefill_blocks_constant;
1379
1380 ECA_LOG_MSG(ECA_LOGGER::system_objects,
1381 "Prefill loops: " +
1382 kvu_numtostr(prefill_threshold_rep) +
1383 " (blocksize " +
1384 kvu_numtostr(buffersize()) + ").");
1385 }
1386
1387 /**
1388 *
1389 * Called only from init_connection_to_chainsetup().
1390 */
init_servers(void)1391 void ECA_ENGINE::init_servers(void)
1392 {
1393 if (csetup_repp->midi_devices.size() > 0) {
1394 use_midi_rep = true;
1395 ECA_LOG_MSG(ECA_LOGGER::info, "Initializing MIDI-server.");
1396 csetup_repp->midi_server_repp->init();
1397 }
1398 }
1399
1400 /**
1401 * Called only from init_connection_to_chainsetup().
1402 */
init_chains(void)1403 void ECA_ENGINE::init_chains(void)
1404 {
1405 mixslot_repp->number_of_channels(max_channels());
1406 mixslot_repp->event_tag_set(SAMPLE_BUFFER::tag_mixed_content);
1407 mixslot_repp->event_tag_set(SAMPLE_BUFFER::tag_var_length, false);
1408
1409 cslots_rep.resize(chains_repp->size());
1410 for(size_t n = 0; n < cslots_rep.size(); n++) {
1411 cslots_rep[n] = new SAMPLE_BUFFER(buffersize(), max_channels());
1412 cslots_rep[n]->event_tag_set(SAMPLE_BUFFER::tag_var_length, false);
1413 }
1414
1415 for (unsigned int c = 0; c != chains_repp->size(); c++) {
1416 int inch = (*inputs_repp)[(*chains_repp)[c]->connected_input()]->channels();
1417 int outch = (*outputs_repp)[(*chains_repp)[c]->connected_output()]->channels();
1418 (*chains_repp)[c]->init(cslots_rep[c], inch, outch);
1419 }
1420 }
1421
1422 /**
1423 * Frees all reserved resources.
1424 *
1425 * @post status() == ECA_ENGINE::engine_status_notready
1426 * @post is_valid() != true
1427 */
cleanup(void)1428 void ECA_ENGINE::cleanup(void)
1429 {
1430 if (csetup_repp != 0) {
1431 csetup_repp->toggle_locked_state(true);
1432 vector<CHAIN*>::iterator q = csetup_repp->chains.begin();
1433 while(q != csetup_repp->chains.end()) {
1434 if (*q != 0) {
1435 (*q)->disconnect_buffer();
1436 }
1437 ++q;
1438 }
1439 csetup_repp->toggle_locked_state(false);
1440 }
1441
1442 csetup_repp = 0;
1443
1444 // --
1445 DBC_ENSURE(status() == ECA_ENGINE::engine_status_notready);
1446 DBC_ENSURE(is_valid() != true);
1447 // --
1448 }
1449
1450 /**
1451 * Updates 'input_chain_count_rep' and
1452 * 'output_chain_count_rep'.
1453 */
update_cache_chain_connections(void)1454 void ECA_ENGINE::update_cache_chain_connections(void)
1455 {
1456 input_chain_count_rep.resize(inputs_repp->size());
1457 for(unsigned int n = 0; n < inputs_repp->size(); n++) {
1458 input_chain_count_rep[n] =
1459 csetup_repp->number_of_attached_chains_to_input(csetup_repp->inputs[n]);
1460 }
1461
1462 output_chain_count_rep.resize(outputs_repp->size());
1463 for(unsigned int n = 0; n < outputs_repp->size(); n++) {
1464 output_chain_count_rep[n] =
1465 csetup_repp->number_of_attached_chains_to_output(csetup_repp->outputs[n]);
1466 }
1467 }
1468
1469 /**
1470 * Update system latency values for multitrack
1471 * recording.
1472 */
update_cache_latency_values(void)1473 void ECA_ENGINE::update_cache_latency_values(void)
1474 {
1475 if (csetup_repp->multitrack_mode() == true &&
1476 csetup_repp->multitrack_mode_offset() == -1) {
1477 long int in_latency = -1;
1478 for(unsigned int n = 0; n < realtime_inputs_rep.size(); n++) {
1479 if (in_latency == -1) {
1480 in_latency = realtime_inputs_rep[n]->latency();
1481 }
1482 else {
1483 if (in_latency != realtime_inputs_rep[n]->latency()) {
1484 ECA_LOG_MSG(ECA_LOGGER::info,
1485 "WARNING: Latency mismatch between input objects!");
1486 }
1487 }
1488
1489 ECA_LOG_MSG(ECA_LOGGER::user_objects,
1490 "Input latency for '" +
1491 realtime_inputs_rep[n]->name() +
1492 "' is " + kvu_numtostr(in_latency) + ".");
1493
1494 }
1495
1496 long int out_latency = -1;
1497 for(unsigned int n = 0; n < realtime_outputs_rep.size(); n++) {
1498 if (out_latency == -1) {
1499 if (realtime_outputs_rep[n]->prefill_space() > 0) {
1500 long int max_prefill = prefill_threshold_rep * buffersize();
1501 if (max_prefill > realtime_outputs_rep[n]->prefill_space()) {
1502 max_prefill = realtime_outputs_rep[n]->prefill_space();
1503 }
1504 out_latency = max_prefill + realtime_outputs_rep[n]->latency();
1505 }
1506 else
1507 out_latency = realtime_outputs_rep[n]->latency();
1508 }
1509 else {
1510 if ((realtime_outputs_rep[n]->prefill_space() > 0 &&
1511 out_latency != (prefill_threshold_rep * buffersize()) + realtime_outputs_rep[n]->latency()) ||
1512 (realtime_outputs_rep[n]->prefill_space() == 0 &&
1513 out_latency != realtime_outputs_rep[n]->latency())) {
1514 ECA_LOG_MSG(ECA_LOGGER::info,
1515 "WARNING: Latency mismatch between output objects!");
1516 }
1517 }
1518
1519 ECA_LOG_MSG(ECA_LOGGER::user_objects,
1520 "Output latency for '" +
1521 realtime_outputs_rep[n]->name() +
1522 "' is " + kvu_numtostr(out_latency) + ".");
1523 }
1524
1525 recording_offset_rep = (out_latency > in_latency ?
1526 out_latency : in_latency);
1527
1528 if (recording_offset_rep % buffersize()) {
1529 ECA_LOG_MSG(ECA_LOGGER::info,
1530 "WARNING: Recording offset not divisible with chainsetup buffersize.");
1531 }
1532
1533 ECA_LOG_MSG(ECA_LOGGER::user_objects,
1534 "recording offset is " +
1535 kvu_numtostr(recording_offset_rep) +
1536 " samples.");
1537 }
1538 else if (csetup_repp->multitrack_mode() == true) {
1539 /* multitrack_mode_offset() explicitly given (not -1) */
1540 recording_offset_rep = csetup_repp->multitrack_mode_offset();
1541 }
1542 else {
1543 recording_offset_rep = 0;
1544 }
1545 }
1546
1547 /**
1548 * Assigns input and output objects in lists of realtime
1549 * and nonrealtime objects.
1550 */
create_cache_object_lists(void)1551 void ECA_ENGINE::create_cache_object_lists(void)
1552 {
1553 for(unsigned int n = 0; n < inputs_repp->size(); n++) {
1554 if (AUDIO_IO_DEVICE::is_realtime_object((*inputs_repp)[n]) == true) {
1555 realtime_inputs_rep.push_back(static_cast<AUDIO_IO_DEVICE*>((*inputs_repp)[n]));
1556 realtime_objects_rep.push_back(static_cast<AUDIO_IO_DEVICE*>((*inputs_repp)[n]));
1557 }
1558 else {
1559 non_realtime_inputs_rep.push_back((*inputs_repp)[n]);
1560 non_realtime_objects_rep.push_back((*inputs_repp)[n]);
1561 }
1562 }
1563 DBC_CHECK(static_cast<int>(realtime_inputs_rep.size()) == csetup_repp->number_of_realtime_inputs());
1564
1565 for(unsigned int n = 0; n < outputs_repp->size(); n++) {
1566 if (AUDIO_IO_DEVICE::is_realtime_object((*outputs_repp)[n]) == true) {
1567 realtime_outputs_rep.push_back(static_cast<AUDIO_IO_DEVICE*>((*outputs_repp)[n]));
1568 realtime_objects_rep.push_back(static_cast<AUDIO_IO_DEVICE*>((*outputs_repp)[n]));
1569 }
1570 else {
1571 non_realtime_outputs_rep.push_back((*outputs_repp)[n]);
1572 non_realtime_objects_rep.push_back((*outputs_repp)[n]);
1573 }
1574 }
1575 DBC_CHECK(static_cast<int>(realtime_outputs_rep.size()) == csetup_repp->number_of_realtime_outputs());
1576 }
1577
1578 /**
1579 * Called only from class constructor.
1580 */
init_profiling(void)1581 void ECA_ENGINE::init_profiling(void)
1582 {
1583 impl_repp->looptimer_low_rep = static_cast<double>(buffersize()) / csetup_repp->samples_per_second();
1584 impl_repp->looptimer_mid_rep = static_cast<double>(buffersize() * 2) / csetup_repp->samples_per_second();
1585 impl_repp->looptimer_high_rep = static_cast<double>(buffersize()) * prefill_threshold_rep / csetup_repp->samples_per_second();
1586
1587 impl_repp->looptimer_rep.set_lower_bound_seconds(impl_repp->looptimer_low_rep);
1588 impl_repp->looptimer_rep.set_upper_bound_seconds(impl_repp->looptimer_high_rep);
1589 impl_repp->looptimer_range_rep.set_lower_bound_seconds(impl_repp->looptimer_mid_rep);
1590 impl_repp->looptimer_range_rep.set_upper_bound_seconds(impl_repp->looptimer_mid_rep);
1591 }
1592
1593 /**
1594 * Prints profiling information to stderr.
1595 */
dump_profile_info(void)1596 void ECA_ENGINE::dump_profile_info(void)
1597 {
1598 long int slower_than_rt = impl_repp->looptimer_rep.event_count() -
1599 impl_repp->looptimer_rep.events_under_lower_bound() -
1600 impl_repp->looptimer_rep.events_over_upper_bound();
1601
1602 cerr << "*** profile begin ***" << endl;
1603 cerr << "Loops faster than realtime: " << kvu_numtostr(impl_repp->looptimer_rep.events_under_lower_bound());
1604 cerr << " (<" << kvu_numtostr(impl_repp->looptimer_low_rep * 1000, 1) << " msec)" << endl;
1605 cerr << "Loops slower than realtime: " << kvu_numtostr(slower_than_rt);
1606 cerr << " (>=" << kvu_numtostr(impl_repp->looptimer_low_rep * 1000, 1) << " msec)" << endl;
1607 cerr << "Loops slower than realtime: " << kvu_numtostr(impl_repp->looptimer_range_rep.events_over_upper_bound());
1608 cerr << " (>" << kvu_numtostr(impl_repp->looptimer_mid_rep * 1000, 1) << " msec)" << endl;
1609 cerr << "Loops exceeding all buffering: " << kvu_numtostr(impl_repp->looptimer_rep.events_over_upper_bound());
1610 cerr << " (>" << kvu_numtostr(impl_repp->looptimer_high_rep * 1000, 1) << " msec)" << endl;
1611 cerr << "Total loops: " << kvu_numtostr(impl_repp->looptimer_rep.event_count()) << endl;
1612 cerr << "Fastest/slowest/average loop time: ";
1613 cerr << kvu_numtostr(impl_repp->looptimer_rep.min_duration_seconds() * 1000, 1);
1614 cerr << "/";
1615 cerr << kvu_numtostr(impl_repp->looptimer_rep.max_duration_seconds() * 1000, 1);
1616 cerr << "/";
1617 cerr << kvu_numtostr(impl_repp->looptimer_rep.average_duration_seconds() * 1000, 1);
1618 cerr << " msec." << endl;
1619 cerr << "*** profile end ***" << endl;
1620 }
1621
1622 /**********************************************************************
1623 * Engine implementation - Private functions for signal routing
1624 **********************************************************************/
1625
1626 /**
1627 * Reads audio data from input objects.
1628 *
1629 * context: J-level-1 (see
1630 */
inputs_to_chains(void)1631 void ECA_ENGINE::inputs_to_chains(void)
1632 {
1633 /**
1634 * - go through all inputs
1635 * - depending on connectivity, read either to a mixdown slot, or
1636 * directly to a per-chain slot
1637 */
1638
1639 for(size_t inputnum = 0; inputnum < inputs_repp->size(); inputnum++) {
1640
1641 if (input_chain_count_rep[inputnum] > 1) {
1642 /* case-1a: read buffer from input 'inputnum' to 'mixslot';
1643 * later (1b) the data is copied to each per-chain slow
1644 * to which input is connected to */
1645
1646 mixslot_repp->length_in_samples(buffersize());
1647
1648 if ((*inputs_repp)[inputnum]->finished() != true) {
1649 (*inputs_repp)[inputnum]->read_buffer(mixslot_repp);
1650 if ((*inputs_repp)[inputnum]->finished() != true) {
1651 inputs_not_finished_rep++;
1652 }
1653 }
1654 else {
1655 /* note: no more input data for this change (N:1 input-chain case) */
1656 mixslot_repp->make_empty();
1657 }
1658 }
1659 for (size_t c = 0; c != chains_repp->size(); c++) {
1660 if ((*chains_repp)[c]->connected_input() == static_cast<int>(inputnum)) {
1661 if (input_chain_count_rep[inputnum] == 1) {
1662 /* case-2: read buffer from input 'inputnum' to chain 'c' */
1663 cslots_rep[c]->length_in_samples(buffersize());
1664
1665 if ((*inputs_repp)[inputnum]->finished() != true) {
1666 (*inputs_repp)[inputnum]->read_buffer(cslots_rep[c]);
1667 if ((*inputs_repp)[inputnum]->finished() != true) {
1668 inputs_not_finished_rep++;
1669 }
1670 }
1671 else {
1672 /* note: no more input data for this change (1:1 input-chain case) */
1673 cslots_rep[c]->make_empty();
1674 }
1675
1676 /* note: input connected to only one chain, so no need to
1677 iterate through the other chains */
1678 break;
1679 }
1680 else {
1681 /* case-1b: input connected to chain 'n', copy 'mixslot' to
1682 * the matching per-chain slot */
1683 cslots_rep[c]->copy_all_content(*mixslot_repp);
1684 }
1685 }
1686 }
1687 }
1688 }
1689
1690 /**
1691 * context: J-level-1
1692 */
process_chains(void)1693 void ECA_ENGINE::process_chains(void)
1694 {
1695 vector<CHAIN*>::const_iterator p = chains_repp->begin();
1696 while(p != chains_repp->end()) {
1697 (*p)->process();
1698 ++p;
1699 }
1700 }
1701
mix_to_outputs_divide_helper(const SAMPLE_BUFFER * from,SAMPLE_BUFFER * to,int divide_by,bool first_time)1702 void mix_to_outputs_divide_helper(const SAMPLE_BUFFER *from, SAMPLE_BUFFER *to, int divide_by, bool first_time)
1703 {
1704 if (first_time == true) {
1705 // this is the first output connected to this chain
1706 if (from->number_of_channels() < to->number_of_channels()) {
1707 to->make_silent();
1708 }
1709 to->copy_matching_channels(*from);
1710 to->divide_by(divide_by);
1711 }
1712 else {
1713 to->add_with_weight(*from, divide_by);
1714 }
1715 }
1716
mix_to_outputs_sum_helper(const SAMPLE_BUFFER * from,SAMPLE_BUFFER * to,bool first_time)1717 void mix_to_outputs_sum_helper(const SAMPLE_BUFFER *from, SAMPLE_BUFFER *to, bool first_time)
1718 {
1719 if (first_time == true) {
1720 // this is the first output connected to this chain
1721 if (from->number_of_channels() < to->number_of_channels()) {
1722 to->make_silent();
1723 }
1724 to->copy_matching_channels(*from);
1725 }
1726 else {
1727 to->add_matching_channels(*from);
1728 }
1729 }
1730
1731 /**
1732 * context: J-level-1
1733 */
mix_to_outputs(bool skip_realtime_target_outputs)1734 void ECA_ENGINE::mix_to_outputs(bool skip_realtime_target_outputs)
1735 {
1736 for(size_t outputnum = 0; outputnum < outputs_repp->size(); outputnum++) {
1737 if (skip_realtime_target_outputs == true) {
1738 if (csetup_repp->is_realtime_target_output(outputnum) == true) {
1739 ECA_LOG_MSG(ECA_LOGGER::system_objects,
1740 "Skipping rt-target output " +
1741 (*outputs_repp)[outputnum]->label() + ".");
1742 continue;
1743 }
1744 }
1745
1746 int count = 0;
1747
1748 /* FIXME: number_of_channels() may end up allocating memory! */
1749 mixslot_repp->number_of_channels((*outputs_repp)[outputnum]->channels());
1750
1751 for(size_t n = 0; n != chains_repp->size(); n++) {
1752 // --
1753 // if chain is already released, skip
1754 // --
1755 if ((*chains_repp)[n]->connected_output() == -1) {
1756 // --
1757 // skip, if chain is not connected
1758 // --
1759 continue;
1760 }
1761
1762 if ((*chains_repp)[n]->connected_output() == static_cast<int>(outputnum)) {
1763 // --
1764 // output is connected to this chain
1765 // --
1766 if (output_chain_count_rep[outputnum] == 1) {
1767 // --
1768 // there's only one output connected to this chain,
1769 // so we don't need to mix anything
1770 // --
1771 (*outputs_repp)[outputnum]->write_buffer(cslots_rep[n]);
1772 if ((*outputs_repp)[outputnum]->finished() == true)
1773 /* note: loop devices always connected both as inputs as
1774 * outputs, so their finished status must not be
1775 * counted as an error (like for other output types) */
1776 if (dynamic_cast<LOOP_DEVICE*>((*outputs_repp)[outputnum]) == 0)
1777 outputs_finished_rep++;
1778 break;
1779 }
1780 else {
1781 ++count;
1782
1783 if (csetup_repp->mix_mode() == ECA_CHAINSETUP::cs_mmode_avg)
1784 mix_to_outputs_divide_helper(cslots_rep[n], mixslot_repp, output_chain_count_rep[outputnum], (count == 1));
1785 else
1786 mix_to_outputs_sum_helper(cslots_rep[n], mixslot_repp, (count == 1));
1787
1788 mixslot_repp->event_tags_add(*cslots_rep[n]);
1789
1790 if (count == output_chain_count_rep[outputnum]) {
1791 (*outputs_repp)[outputnum]->write_buffer(mixslot_repp);
1792 if ((*outputs_repp)[outputnum]->finished() == true)
1793 /* note: loop devices always connected both as inputs as
1794 * outputs, so their finished status must not be
1795 * counted as an error (like for other output types) */
1796 if (dynamic_cast<LOOP_DEVICE*>((*outputs_repp)[outputnum]) == 0)
1797 outputs_finished_rep++;
1798 }
1799 }
1800 }
1801 }
1802 }
1803 }
1804
1805 /**********************************************************************
1806 * Engine implementation - Obsolete functions
1807 **********************************************************************/
1808