File: ecasound_programmers_guide.txt

package info (click to toggle)
ecasound 2.9.3-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 6,292 kB
  • sloc: cpp: 39,475; sh: 4,335; lisp: 1,918; ansic: 1,883; makefile: 888; python: 617; ruby: 202
file content (1207 lines) | stat: -rw-r--r-- 43,907 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
:editor: -*- mode: fundamental; tab-width: 4; indent-tabs-mode: nil -*-
:version: 20090419-9
:syntax: loosely follows restructured text, http://docutils.sourceforge.net/rst.html
:author: Kai Vehmanen

===========================
Ecasound Programmer's Guide
===========================

.. #################################################################
.. #################################################################

.. contents::

Preface
~~~~~~~

This document describes how Ecasound and the related libraries
work, how to use them, how to extend and add features and other 
similar issues. Before reading this document, you should first take a 
look at other available documentation (especially 
Ecasound Users's Guide).

If not otherwise specified, all documentation refers to the latest
Ecasound version.

.. #################################################################
.. #################################################################

Document history
~~~~~~~~~~~~~~~~

Hmm, why doesn't this work...?

::

| 19.04.2009 - Minor updates to NetECI and ECA_CONTROL.
| 21.08.2005 - Typos fixed, removed duplicated section on audio
|              routing. Minor updates to various sections.
| 25.04.2005 - Minor updates.
| 28.03.2005 - Added section about "Source code markup", update the
|              "Design principles" section.
| 13.03.2005 - Converted from LaTeX to ascii.
| 23.10.2004 - Added section "EIAM commands" that covers adding
|              new EIAM commands.
| 18.11.2003 - Typo fixes. Updated documentation to reflect the new
|              naming convention (ecasound refers to the binary,
|              Ecasound refers to the whole package).
| 07.11.2002 - Added documentation for NetECI.
| 25.10.2002 - Added "Checklist for Audio Object Implementations".
| 17.10.2002 - Added a warning against direct use of libecasound
|              and libkvutils. Using ECI is from now on the 
|              preferred way of using ecasound as a development
|              platform. Rewrote the "Versioning" section.
| 02.10.2002 - Added the "Protocols and Interfaces" chapter.
| 29.04.2002 - Added chapter about "Unit Tests".
| 28.04.2002 - Revised namespace policy (see chapter
|              on namespaces), replaced references to
|              obsolete ECA_DEBUG with a description
|              of the new ECA_LOGGER subsystem.
| 27.02.2002 - Rewrote the "Control flows" chapter according 
|              to the structural changes made in 2.1dev8. Added
|              a "References" section.
| 31.01.2002 - Reorganization of document structure. New chapter 
|              about "Library organization".
| 19.12.2001 - Added chapter about include hierarchies.
| 28.10.2001 - Lots of changes to the "Object maps" chapter.
| 21.10.2001 - Added this history section.

.. #################################################################
.. #################################################################

General programming guidelines
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Design and programming principles
=================================

The following sections describe some of the key design 
principles that have been guiding Ecasound development.

Open and generic design
-----------------------

Over the years Ecasound's core design has been revised many times.
The aim has been to keep the core flexible enough, so it can
be easily adapted to new use cases.

Object-orientation
------------------

Ecasound is written in C++ (as specified in 1997 ANSI/ISO C++ standard). 
Common object-oriented design practices should be utilized. At same time 
overuse of object-orientation should be avoided. Object-orientation is 
a very effective design method, but not the only one. Sometimes other 
approaches work better.

Data hiding
-----------

This design principle deserves to be mentioned separately. Whenever 
possible, the actual data representation and implementation details
should always be hidden. This allows to make local implementation 
changes without affecting other parts of the code base. It cannot
be emphasized enough how important this goal is for large software 
projects like Ecasound.

Design by contract
------------------

When writing a new routine, in addition to the actual code,  
also routine's behaviour should be described as accurately as 
possible using preconditions and postconditions to describe
the external side-effects (how it changes the object state, what 
is the relation between arguments and return values).

The preconditions should specify all requirements and 
assumptions related to routine's inputs. If the caller violates 
this specification, routine is not responsible for the error.

The postconditions should specify what statements hold true
when routine has been executed. This information helps the
caller to better understand how the routine works and
to identify implementation bugs.

Ideally, these conditions prove that the routine works 
correctly. Writing a complete description of a routine can be
difficult, but the benefits of this approach should be clear. 
When you call a well-defined routine, a) you know what 
parameter values it accepts, b) you know what it does and c) if 
errors occur, it's easier to pinpoint the faulty routine. 

In practice describing routines is done by combining verbose
comments and defining pre/postconditions. As C++ doesn't directly 
support pre/postconditions, the DEFINITION_BY_CONTRACT and DBC tools 
provided by libkvutils are used.

Routine side effects
--------------------

A clear distinction should be made between routines that 
have side-effects (=methods, processors, modifiers; routines that
change object's state) and const routines (=functions, observers).

To make monitoring side effects easier, all Ecasound classes 
should be const-correct. A object is const-correct if a function
taking only a single argument that is a const reference to that object
is not able, without explicit casting, to obtain a non-const
reference to that same object (or a portion thereof) from within
the function body.

Sanity checks
-------------

Sanity checks are done only to prevent crashes. All effects
and operators should accept also "insane" parameters. For example,
the amplifier effect accepts -100.0% as the gain value. This of course 
results in inverted sample data, which is a useful outcome. 
As Ecasound is supposed to be a tool for creative work and 
experimenting, the decisions on which parameters are useful
for audio processing should not be made in source code.

Error handling
--------------

Two specific things worth mentioning: First, the standard UNIX-style 
error handling, where functions performing actions return an integer 
value, is not used in Ecasound. As described in the above section 
Routine side effects, all routines are either modifiers or
observers, not both. So when using Ecasound APIs, you first perform an
action (modifying function), and then afterwards check what happened
(using an observer function).

Exceptions
----------

C++ exceptions are used in Ecasound. Exception based error
handling has its problems, but in some cases it is clearly the best
option. Exceptions are most useful in situations where 
controlled error recovery is very difficult, and in situations
where errors occurs only very rarely. This allows callers to 
avoid constantly checking returns values for functions that 
in normal use never fail. Another special case is handling critical
errors that occur in class contructors.

Using exceptions for anything other than pure error handling 
is to be avoided at all cost. And when exceptions are used,
their use must be specified in function prototypes. This is important,
as clients need to know what exceptions can be thrown. C++ 
unfortunately doesn't require strict exception prototypes, so
this issue requires extra care.

A list of specific cases where exceptions are used follows:

AUDIO_IO - open()
  This method is used for initializing external connections (opening
  files or devices, loading shared libraries, opening IPC connections). 
  It's impossible to know in advance what might happen. In many cases it
  is also useful to get more verbose information about the problem 
  that caused open() to fail. Throwing an exception is an excellent way
  to achieve this.

ECA_CHAINSETUP - enable()
  TBD

ECA_CHAINSETUP - load_from_file, save() and save_to_file
  TBD

ECA_SESSION - constructor
  TBD	   


Coding style, naming conventions and source code markup
=======================================================

This section describes some of the conventions used in
Ecasound development. As a general rule, one should 
adapt to whatever style and conventions used in 
already existing code.

Variable and type naming
------------------------

Variable names are all lower case and words are separated with
underscores (int very_long_variable_name_with_underscores). Class data
members are marked with "_rep" postfix. Data members which are
pointers are marked with "_repp". Index-style short variable names 
(n, m, etc.) are only used in local scopes. Enum types 
have capitalized names (Some_enum).

Use of macro processing should be avoided, but when necessary,
macro names should be capitalized.

Package specific
----------------

libecasound, ecasound, ecatools, libkvutils
    Class names are all in upper case and words separated with underscores
    (class ECA_CONTROL_BASE). This a standard style in Eiffel programming.

libqtecasound, qtecasound, ecawave
    Qt-style is used when naming classes (class QELevelMeter), otherwise
    same as above.

Private classes
---------------

Some classes are divided into public and private parts. This is
done to make it easier to maintain binary-level compatibility 
between library versions, and to get rid of header file 
dependencies. 

Private classes have a "_impl" postfix in their name. They
are usually stored into separate files which also use the
"_impl" notation.

For instance the ECA_ENGINE class (eca-engine.h) has
a private class ECA_ENGINE_impl (eca-engine_impl.h). 
Access to ECA_ENGINE_impl is only allowed to ECA_ENGINE 
member functions. In addition, the private header file 
(eca-engine_impl.h) is only included from the ECA_ENGINE 
implementation file (eca-engine.cpp). This allows us to 
add new data members to ECA_ENGINE_impl without breaking 
the binary interface.

Unit tests
----------

Unit tests are used for verifying that modules work as intended. 
A test for component, with a public interface defined in 
"prefix-component.h", should located in
"prefix-component_test.h". The test itself should implement
the ECA_TEST_CASE interface. In addition, generic test cases 
should be added to ECA_TEST_REPOSITORY - see 
"libecasound/eca-test-repository.cpp".

Source code markup
------------------

In addition to the Javadoc-style source code documentation (see 
'Documentation style' section), inline commentary markup is used 
to document important code segments. Use of common markup notation 
is preferred (for example it is nice to be able to grep for a list 
of open items in certain part of the codebase):

- Known bugs, unhandled cases, and missing features should 
  be marked with "FIXME: description" comments.

- Explanatory notes that help to understand the code
  should be marked with "NOTE: description".

Style updates
-------------

The general rule is to use consistant style within one
source file (i.e. compilation unit). Updates to style issues 
are also done with the same granularity. The following global 
updates have been made so far to the sources:

eca-style-version: 1
    The opening braces of multi-line functions should be put on a separate
    line, at column 1, instead of being on the same line with 
    function signature. This change only applies to functions, in
    other words the K&R style is followed.

eca-style-version: 2
    Extra parenthesis around "return" values should be removed 
    ("return" is a keyword, not a function).

eca-style-version: 3
    The module name prefix, for example "(eca-session) ", should
    be removed from ECA_LOG_MSG() statements. The module prefix
    is added automatically to the debug messages when debug
    level "module_names" is activated.

If a file has been updated according to these guidelines,
the appropriate style version should be mentioned at the
start of the file ("Attributes: eca-style-version: XXX").
     

Physical level organization
===========================

Ecasound libraries and applications are divided into distribution 
packages, directories and file groups. 

Include hierarchies
-------------------

Include statements that are not stricly necessary should be dropped!
Not only do they cause unwanted dependencies, they also create more
work for the compiler (Ecasound already takes painfully long to 
compile). Some rules to follow:

- In header files, no extra header files should be defined.
  For instance in many cases it's enough to state that 
  object SOME_TYPE is a class without need for the full 
  implementation; so instead of "\#include "sometype.h", use
  "class SOME_TYPE;".

- For modules with separate implementation and header files, 
  dependencies to other modules need not be 
  stated in both.

- Direct dependencies to outside modules must always 
  be mentioned directly. It's easy to unknowingly include 
  a required header file via some other header file. This
  should be avoided as it hides real dependencies.

- When including headers for more special services, it's
  good to add a comment why this header file is needed.

Distribution packages
---------------------

As an example, Ecasound and Ecawave are distributed as separate
packages. This decision has been made because a) they are clearly 
independent, b) they have different external dependencies, and c)
they address different target uses. 

Directories
-----------

It's convenient to organize larger sets of source code into separate
directories. For instance libecasound and ecatools components of 
the Ecasound package are located in separate directories.

File groups
-----------

Although files are divided in directories and subdirectories, 
there's still a need to logically group a set of source files based
on their use and role in the overall design. As the use of C++ 
namespaces is very limited in Ecasound (to avoid portability
problems), filename prefixes are used for grouping files. Here's
a short list of commonly used prefixes. 

audioio*.{cpp,h}
    Audio device and file input/output.
audiofx*.{cpp,h}
    Audio effects and other DSP-related code.
audiogate*.{cpp,h}
    Gate operators.
eca*.{cpp,h}
    Core functionality.
midi*.{cpp,h}
    MIDI input/output devices, handlers and controller code.
osc*.{cpp,h} 
    Oscillator and other controller sources.
qe*.{cpp,h}
    Generic prefix for files utilizing both Qt and Ecasound libraries.
samplebuffer*.{cpp,h}
    Routines and helper functions for processing audio data buffers.

You should note that these are just recommendations - there are no
strict rules on how files should be named.

C++ std namespace
-----------------

The preferred way to access C++ standard library functions is 
to use explicit namespace selectors ("std::string") in public 
headers files, and "using declarations" in the implementation 
parts ("using std::string"). It's also possible to import the 
whole std namespace ("using namespace std;") in the beginning
of an implementation file (but never in headers!).


Documentation style
===================

Javadoc-style class documentation is the preferred style.
Class members can be documented either when they are declared (header
files), or when they are defined. Especially when specifying
complicated interfaces, it's better to put documentation in the
definition files. This way the header files remain compact and serve 
better as a reference. 

Here's a few general documentation guide lines:

Use of 3rd person
    "Writes samples to memory." instead of "Write samples to memory."
Sentences start with a verb
    "Writes samples to memory." instead of "Samples are written to memory."
Use "this" instead of "the"
    "Get controllers connected to this effect." instead of "Get controllers connected to the effect.


Versioning
==========

All Ecasound releases have a distinct version number. The
version number syntax is x.y[.z][-extraT], where x and
y are the major and minor numbers, and z is an optional
revision number. To test major changes, separate -preX or 
-rcX versions can be distributed before the official release.

In addition, all Ecasound libraries have a separate interface 
version. The libtool-style version:revision:age versioning
is used. See the libtool documentation for details.

One important thing to note is that the library interface version 
numbers are tied to the source-code level interfaces, not the binary
interfaces. Because binary interfaces are not explicitly versioned,
applications should always statically link against the Ecasound 
libraries. Also, any private source-code interfaces, ie. header
files with a "_impl.h" postfix, are not part of the versioned
public interface. Applications should not rely on these interfaces!

All changes in the public interfaces are documented in library
specific ChangeLog files. These files are usually located in the
top-level source directory of the versioned library.

One thing to note is that Ecasound's versioning practises have 
changed quite a few times during the project's history. The
rules described above only apply to Ecasound 2.2.0 and newer
releases.

.. #################################################################
.. #################################################################

How Ecasound works?
~~~~~~~~~~~~~~~~~~~

Example use cases
=================

Here's a few common use cases how Ecasound can be used.

Simple non-interactive processing
---------------------------------

One input is processed and then written to one output. This includes effect 
processing, normal sample playback, format conversions, etc.

Multitrack mixing
-----------------

Multiple inputs are mixed into one output.

Real-Time effect processing
---------------------------

There's at least one real-time input and one real-time output.
Signal is sampled from the real-time input, processed and
written to the real-time output.

One-track recording
-------------------

One real-time input is processed and written to one or 
more outputs.

Multitrack recording
--------------------

The most common situation is that there are two separate
chains. First one consists of real-time input routed to a
non-real-time output. This is the recording chain. The
other one is the monitor chain and it consists of one or
more non-real-time inputs routed to a real-time output.
You could also route your real-time input to the monitoring
chain, but this is not recommended because of severe
timing problems. To synchronize these two separate chains,
Ecasound uses a special multitrack mode (which should be
enabled automatically).

Recycling a signal through external devices
-------------------------------------------

Just like multirack recording. The only difference is
that real-time input and output are externally
connected.


Audio signal routing
====================

Basic audio flow inside an Ecasound chainsetup is as follows: Audio 
data is routed from input audio objects to a group of chains. In
the chains audio data is processed using chain operators. After
processing data is routed to output objects.

Using internal loop devices, it's also possible to route signals 
from one chain to another. Looping causes extra latency of one
engine cycle. 

Routing of signals is based on the ability to assign inputs and 
outputs to multiple chains. Assigning an input object to multiple
chains divides the audio signal generating multiple copies of
the original input data. Similarly with an output object, data from
multiple chains is mixed together to one output object.

Control flow
============

Batch operation
---------------

When Ecasound is run in batch mode, the program flow is simple.
To store the session data, a ECA_SESSION object is first
created. The created object is then passed as an argument for
ECA_CONTROL class constructor.

All required configuration of inputs, outputs and chain 
operators is done using the services provided by ECA_CONTROL.
Once a valid chainsetup is ready for processing, batch 
operation is initiated by issuing ECA_CONTROL::run(). This
function will block until processing is finished.

Interactive operation
---------------------

Interactive operation is similar to batch operation. The 
important difference is that processing is started with
ECA_CONTROL::start(). Unlike run(), start() does not 
block the calling thread. This makes it possible to 
continue using the ECA_CONTROL interface while engine
is running in the background. 

Two important concepts to understand when 
working with ECA_CONTROL are the selected 
and connected chainsetups. ECA_CONTROL allows 
working with multiple chainsetups, but only one
of them can be edited at a time, and similarly 
only one at a time can be connected to the 
processing engine. For instance if you add a new
input object with add_audio_input(), it is 
added to the selected chainsetup. Similarly when
you issue start(), the connected chainsetup is 
started.

.. #################################################################
.. #################################################################

Library organization
~~~~~~~~~~~~~~~~~~~~

The primary source for class documentation is header files.
A browsable version of header documentation is at
http://nosignal.fi/ecasound/Documentation
Anyway, let's look at the some central classes.


Interfaces for external use
===========================

The following classes of libecasound are designed as
primary interfaces for external use. The approach 
is based on the Facade (GoF185) design pattern. The primary 
goals are concentrating functionality, and maintaining 
a higher level of interface stability.

ECA_CONTROL - eca-control.h 
---------------------------

ECA_CONTROL represents the whole public interface offered by 
libecasound. The primary purpose of ECA_CONTROL is to offer a 
consistent, straightforward interface for controlling Ecasound. 
The interface is also designed to be more stable than other 
parts of the library.

On important part of ECA_CONTROL is the functionality for 
interpreting EOS (Ecasound Option Syntax) and EAIM (Ecasound 
Interactive Mode) commands.

ECA_CONTROL_MAIN (eca-control-main.h) is an abstract base class that 
defines a subset of core ECA_CONTROL functionality. This interface
is implemented by e.g. ECA_CONTROL (the default implementation)
and ECA_CONTROL_MT (a thread-safe variant that allows simultaneous
use from multiple threads). 

It is recommended that applications use the subset defined
by ECA_CONTROL_MAIN.

ECA_CONTROL_INTERFACE - eca-control-interface.h
-----------------------------------------------

C++ implementation of the Ecasound Control Interface (ECI) API. See
section "Ecasound Control Interface" for more information.

Core classes
============

This section introduces the core classes, which define the
central data types and are responsible for the main program
logic.

AUDIO_IO_PROXY_SERVER - audioio-proxy-server.h
----------------------------------------------

Implements a audio input/output subsystem that adds
a second layer of buffering between the main processing 
engine and non-real-time audio input and output objects.

Double buffering is needed to guarantee a real-time constrained 
data stream even when dealing with non-real-time objects like
disk files.

CHAIN - eca-chain.h
-------------------

Class representing one abstract audio signal chain. CHAIN
objects consist of chain operators, controllers and their
state information.

ECA_CHAINSETUP - eca-chainsetup.h
---------------------------------

ECA_CHAINSETUP is the central class for storing user-visible 
objects. All inputs, output, chain operator and controller 
objects are attached to some ECA_CHAINSETUP object.

ECA_ENGINE - eca-engine.h 
-------------------------

ECA_ENGINE is the actual processing engine. It is initialized with
a pointer to a ECA_CHAINSETUP object, which has all information 
needed at runtime. In other words ECA_ENGINE is used to execute
the chainsetup. You could say ECA_ENGINE renders the final product
according to instruction given in ECA_CHAINSETUP. 

Processing is started with the exec() member function and
after that, ECA_ENGINE runs on its own. If 'batch_mode' 
is selected (parameter to exec()), one started ECA_ENGINE will 
run until a 'finished' condition is met and then exit 
automatically. Finished means that we have read all available data 
from input sources. Of course if some input has infinite length 
(soundcards for example), processing will never finish. To get 
around this limitation, it's possible to set the processing 
length (see ECA_CONTROL_OBJECTS::set_chainsetup_processing_length_in_seconds()).

If batch mode is not enabled, engine will just perform
the init phase and starts waiting for further instructions. 
These instructions can be send to the engine using 
the ECA_ENGINE::command() member function.

ECA_ENGINE has the following states:

not_ready
    ECA_SESSION object is not ready for processing or 
    ECA_ENGINE hasn't been created
running
    processing
stopped
    processing hasn't been started or it has been stopped
    before completion
finished
    processing has been completed
error
    an error has occured during prosessing

ECA_SESSION - eca-session.h
---------------------------

ECA_SESSION is an abtraction used to represents a group of
chainsetups. At any time, only one chainsetup object at a time
can be active (connected). For modification, one chainsetup
can be set as 'selected'. This means that all configuration
operations are targeted to the selected chainsetup.

The only public access to ECA_SESSION objects is 
through ECA_CONTROL objects.

MIDI_SERVER - midi-server.h
---------------------------

Engine that handles all MIDI input and output.

SAMPLEBUFFER - samplebuffer.h
-----------------------------

Basic unit for representing blocks of sample data. The data type used 
to represent single samples, valid value ranges, channel count and system 
endianess are all specified in "samplebuffer.h" and "sample_specs.h".


Feature and capability interface classes
========================================

Many libecasound classes have similar attribute sets and capabilities. 
To make use of these shared features, most common features have their 
own virtual base classes. All objects that have a particular feature,
inherit the same virtual base class. This makes object grouping
and management easier and less error prone.

DYNAMIC_PARAMETERS<T> - dynamic-parameters.h
--------------------------------------------

Implemented by all classes that provide a set of generic parameters
of type T. Parameter can be observed and modified, and they
usually are identified by a unique name and a more verbose 
description. Number of parameters can vary dynamically. Other 
objects can access these parameters without detailed knowledge of 
the object itself.

ECA_AUDIO_FORMAT - eca-audio-format.h
-------------------------------------

Implemented by all classes that an audio format attribute
set that can be observed and modified.

ECA_AUDIO_POSITION - eca-audio-position.h
-----------------------------------------

Implemented by all classes that need to maintain current audio 
position and length.

ECA_SAMPLERATE_AWARE - eca-samplerate-aware.h
---------------------------------------------

Implemented by all classes that need knowledge of current
sampling rate.

MIDI_CLIENT - midi-client.h
---------------------------

Implemented b all classes that require a connection to 
an instance of MIDI_SERVER.


Object interfaces
=================

Object interfaces define the behaviour for common objects used
by libecasound. The core classes rarely operate on specific
object types, but instead use object interfaces (abstract 
interfaces). Object interfaces are usually abstract C++ classes 
(instances of these classes cannot be created as some of functions
don't yet have a concreate implementation, ie. they pure virtual
functions).

AUDIO_IO - audioio.h
--------------------

Virtual base class for all audio I/O objects. Different types
of audio objects include files, audio devices, sound 
producing program modules, audio server clients, and so on.

More specialized interface classesa are AUDIO_IO_DEVICE (for
real-time audio objects) and AUDIO_IO_BUFFERED (for POSIX-style
buffered i/o). There's also a special AUDIO_IO_MANAGER
interface for managing multiple audio objects of same 
type inside one chainsetup.

CHAIN_OPERATOR - eca-chainop.h
------------------------------

Virtual base class for chain operators.

CONTROLLER_SOURCE - ctrl-source.h
---------------------------------

Virtual base class for all controller sources.

MIDI_IO - midiio.h
------------------

Virtual base for objects capable of reading and writing
raw MIDI data.

MIDI_HANDLER - midi-server.h
----------------------------

Virtual base class for objects capable of receiving 
and processing MIDI data.

Object interface implementations - plugins
==========================================

Majority of the classes in libecasound fall to this category. They 
implement the behaviour of some object interface type. As other
parts of the library only use the object interfaces, these
implementation classes are fairly isolated. Changes made inside object 
implementation have no effect to other parts of the library. 
Similarly new object interface implementations can be added without
modifying the core classes.


Utility classes
===============

TBD

eca-logger.h - ECA_LOGGER
-------------------------

Singleton class that provides an interface to Ecasound's logging 
subsystem. Libecasound sends all log messages to this interface. 
The actual logger implementation can be done in many ways. For example 
in the console mode user-interface of Ecasound, TEXTDEBUG class 
implements the ECA_LOGGER_INTERFACE class interface. It sends all 
messages that have a suitable debug level to the console's standard 
output. On the other hand, in qtecasound, ECA_LOGGER_INTERFACE is 
implemented using a Qt widget.

New ECA_LOGGER_INTERFACE implementations can be registered at
runtime with the ECA_LOGGER::attach_logger() member
function (declared in eca-logger.h).


Object maps
===========

Object maps are central repositories for commonly used objects.
Their main purpose is to add flexibility to handling different 
object types - especially to handling dynamic addition and removal
of whole object types. They provide the following services:

- listing all object types in any of the available 
  categories (for instance, list all effect types)

- creating new object instances based on keyword strings
  (for instance, returns an mp3 object if "foo.mp3" is given
  as keyword)

- adding new object types (object map item is identified by 
  tuple of "keyword, regex expression, object type")

- removing object types

- reverse mapping objects back to keyword strings

In Ecasound, all access to object maps goes throuh the library-wide
ECA_OBJECT_FACTORY class, which provides a set of static functions
to access the object maps.

This system may sound a bit complex, but in practise it is quite
simple and makes a lot of things more easier. For instance, when
adding new object types to the library, you only have to add one
function call which registers the new object; no need to modify any 
other part of the library. It also makes it possible to add new 
types at runtime, including dynamically loaded plugins. 

One special use-case is where an application linked against
libecasound adds its own custom object types on startup. All parts 
of libecasound can use the custom objects, although they are not 
part of library itself.

All objects defined in libecasound are registered in the file
eca-static-object-maps.cpp.

eca-object.h - ECA_OBJECT
-------------------------

A virtual base class that represents an Ecasound object. All objects
handled by the object factory must inherit this class.

eca-object-factory.h - ECA_OBJECT_FACTORY
-----------------------------------------

The public interface to Ecasound's object maps. All its functions
are static.

.. #################################################################
.. #################################################################

Adding new features and components to Ecasound?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Things to remember when writing new C++ classes
===============================================

TBD

Copy constructor and assignment operator
----------------------------------------

Always take a moment to check your copy constructor and the assign 
operation (=operation()). Basicly you have three alternatives: 

- Trust the automatically created default definitons. If you don't
  have any pointers as data members, this isn't necessarily a bad
  choice at all. At least the compiler remembers to copy all members!

- If you have pointers to objects as class data members, you should
  write definitions for both the copy-constructor and the assign
  operation.

- If you are lazy, just declare the two functions as null
  functions, and put them in "private:"_ access scope. At least this way
  nobody will use the functions by accident!


Audio objects
=============

To implement a new audio object type, you must first select which 
top-level class to derive from. Usually this is either AUDIO_IO
(the top-level class), AUDIO_IO_BUFFERED (a more low level interface)
or AUDIO_IO_DEVICE (real-time devices).

The second step is to implement the various virtual functions declared
in the parent classes. These functions can be divided into four
categories: 1) attributes (describes the object and its capabilities), 
2) configuration (routines used for setting up the object), 3) main 
functionality (open, close, input, output, etc) and 4) runtime
information (status info).

Adding the new object to Ecasound is much like adding a new effect
(see the next section). Basicly you just add it to the makefiles and
then register it to the appropriate object map (see below).

Checklist for Audio Object Implementations
------------------------------------------

1. Check that read_buffer() and write_buffer() change the
   internal position with either set_position_in_samples()
   or change_position_in_samples() functions of ECA_AUDIO_POSITION.
   Also, when writing a new file, extend_position() should
   also be called. All this is done automatically if using 
   read_samples() and write_samples() from AUDIO_IO_BUFFERED.

2. If implementing a proxy object, separately consider all public 
   functions of audioio-proxy.h (whether to reimplement or use
   as they are).

3. Check that open() and close() call AUDIO_IO::open() and
   AUDIO_IO::close(), and in the right order.

4. If the object supports seeking, seek_position() must
   be implemented.

5. Check that the set_parameter() and get_parameter() methods 
   work correctly when they are used for saving and restoring
   audio object state (for example cs-edit EIAM command).


Effects and other chain operators
=================================

Write a new class that inherits from CHAIN_OPERATOR or any of its
successors. Implement the necessary routines (init, set/get_parameter, 
process and a default constructor) and add your source files to
libecasound's makefiles. Then all that's left to do is to add your
effect to libecasound/eca-static-object-maps.cpp,
register_default_objects(). Now the new effect can be used just 
like any other Ecasound effect (parameters control, effect presets, etc).

Another way to add effects to Ecasound is to write them as LADSPA
plugins. The API is well documented and there's plenty of
example code available. See http://www.ladspa.org 
for more information.


Differences between audio objects and chain operators
=====================================================

Design-wise, audio objects and effects (chain operators) aren't that 
far away from each other. Many audio apps don't separate these
concepts at all (for instance most UG based synthesizers). In Ecasound 
though, there are some differences:

Input/output:

- audio objects can be opened for reading writing or read\&write
- ... effects are not modal (i.e. modeless)
- audio objects read from, or write to, a buffer
- ... effects get a buffer which they operate on (in-place processing)

Audio format:

- audio objects have a distinct audio format (sample rate, bits,
  channels)
- .... effects should be capable of accepting audio data in any format
  (this is usually easy as Ecasound converts all input data to its
  internal format)

Control:

- audio objects can be opened, closed, prepared, started and stopped
- ... effects have a much simpler running state: either uninitialized or ready-for-processing

Position:

- audio objects have length and position attributes
- ... effects just process buffers and don't need to care about position information

A good example of the similarity between the two types are LADSPA
oscillator plugins. Although they are effects, you can easily use them 
as audio sources (inputs) by specifying:

::

"ecasound -i null -o /dev/dsp -el:sine_fcac,440,1"

 
LADSPA plugins
==============

Ecasound supports LADSPA-effect plugins (Linux Audio Developer's Simple
Plugin API). See LAD mailing list web site for 
more info about LADSPA. Other useful sites are 
LADSPA home page and LADSPA documentation.


EIAM commands
=============

Adding a new interactive mode commands requires changes to the
following files:


- libecasound/eca-iamode-parser_impl.h: Unique id for the new command
  has to be added to enum Commands.

- libecasound/eca-iamode-parser.cpp: The new command must be added
  to the appropriate register_commands_*() function.

- libecasound/eca-iamode-parser.cpp: The new command must be added
  to the appropriate action_requires_*() sets.

- libecasound/eca-control.cpp: The actual implementation of the
  new command.

- Documentation/ecasound-iam_manpage.yo: Documentation must be
  added.

.. #################################################################
.. #################################################################

Application development using the Ecasound framework
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Console mode ecasound - [all languages]
=======================================

This is the easiest way to take advantage of Ecasound features in your
own programs. You can fork ecasound, pipe commands to ecasound's
interactive mode or you can create chainsetup (.ecs) files and load
them to ecasound. You'll be able to do practically anything. The only 
real problem is getting information from ecasound. You'll have to
parse ecasound's ascii output if you want to do this. To make this 
a bit easier, Ecasound offers the wellformed output mode 
and dump-* commands. These can be used to easily parse configuration and 
status information.


Ecasound Control Interface - [C++, C, Python, Perl, ...]
========================================================

Idea behind Ecasound Control Interface (ECI) is to take a subset of 
functionality provided by libecasound, write a simple API for it, and
port it to various languages. At the moment, at least C++, C and
Python implementations of the ECI API are available and part of the
main Ecasound distribution. ECI is heavily based on the Ecasound
Interactive Mode (EIAM), and the services it provides. 

Specific tasks ECI is aimed at:

- 1. automating (scripting in its traditional sense)
- 2. frontends (generic / specialized)
- 3. sound services to other apps


NetECI - [various]
==================

NetECI is a network version of the ECI API. When Ecasound is
started in server mode (see ecasound(1) for the related options), it 
listens for incoming NetECI commands on a TCP socket. Client 
applications can connect to this socket and use the connection to 
control and observe the active session. Multiple clients
can connect to the same session.

The protocol is identical to one used in ECI (see section "Ecasound
Interactive Mode - Well-Formed Output Mode" below). Clients write EIAM
commands to the socket, followed by a CRLF pair. The server will reply
using the well-formed output mode syntax.

See implementation of ecamonitor (part of ecatools), 
for a working example.


Libecasound's ECA_CONTROL class - [C++]
===========================================

Note! Direct use of libecasound and libkvutils is
not recommended anymore! Please use the Ecasound Control Interface
(ECI) instead.

By linking your program to libecasound, you can use the ECA_CONTROL
class for controlling Ecasound. This is a large interface class that
offers routines for controlling all Ecasound features. It's easy
to use while still powerful. Best examples are the utils in ecatools 
directory (most of them are just a couple screenfuls of code). Also, 
qtecasound and ecawave heavily use ECA_CONTROL. Here's a few lines of 
example code:

::

| --cut--
| ECA_SESSION esession;
| ECA_CONTROL ctrl (&esession);
| ctrl.new_chainsetup("default");
| [... other setup routines ]
| ctrl.start(); // starts processing in another thread (doesn't block)
| --cut--
 
If you don't want to use threads, you can run the setup in
batch mode:

::

| --cut--
| ECA_SESSION esession;
| ECA_CONTROL ctrl (&esession);
| ctrl.add_chainsetup("default");
| [... other setup routines ]
| ctrl.run(); // blocks until processing is finished
| --cut--

 
Ecasound classes as building blocks - [C++]
===============================================

Note! Direct use of libecasound and libkvutils is
not recommended anymore! Please use the Ecasound Control Interface
(ECI) instead.
 
You can also use individual Ecasound classes directly.
This means more control, but it also means more work. Here's
another short sample:

| --cut--
| - create a SAMPLE_BUFFER object for storing the samples
| - read samples with an audio I/O object - for example WAVEFILE
| - process sample data with some effect class - for example EFFECT_LOWPASS
| - maybe change the filter frequency with EFFECT_LOWPASS::set_parameter(1, new_value)
| - write samples with an audio I/O object - OSSDEVICE, WAVEFILE, etc.
| --cut--

.. #################################################################
.. #################################################################

Protocols and Interfaces
~~~~~~~~~~~~~~~~~~~~~~~~

Ecasound Interactive Mode - Well-Formed Output Mode
===================================================

By issuing the EIAM command "int-output-mode-wellformed", 
Ecasound will start printing all messages using the following
format:

::

| <message> = <loglevel><sp><msgsize>(<genmsg> | <returnmsg>)
| 
| <loglevel> = <integer>      ; loglevel number
| <msgsize = <integer>        ; size of content in octets
| <genmsg> = <contentblock>   ; generic log message
| <returnmsg> = <sp><returntype><contentblock>
|                             ; EIAM return value message
| <contentblock> = <crlf><content><crlf><crlf>
|                             ; actual content of the message
| <returntype> = "i" | "li" | "f" | "s" | "S" | "e"
|                             ; type of the return value (see ECI/EIAM docs)
| <content> = *<octet>        ; zero or more octets of message content
| 
| <sp> = 0x20                 ; space
| <octet> = 0x00-0xff         ; 8bits of data
| <crlf> = <cr><lf>           ; new line 
| <cr> = 0x0d                 ; carriage return
| <lf> = 0x0a                 ; line feed
| <integer> = +<digit>        ; one or more digits
| <digit> = 0x30-0x39         ; digits 0-9