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