editor:-- mode: fundamental; tab-width: 4; indent-tabs-mode: nil --
Version: 20050821-8
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...?

| 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 sers-and-sef="#ecasound-classes-as-building-blocks-c" id="id85" name="id85">Ecasound classes as building blocks - [C++]
  • Protocols and Interfaces
  • 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...?

    | 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 sers-and-sef="#ecasound-classes-as-building-blocks-c" id="id85" name="id85">Ecasound classes as building blocks - [C++]
  • Protocols and Interfaces
  • 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...?

    | 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 sers-and-sef="#ecasound-classes-as-building-blocks-c" id="id85" name="id85">Ecasound classes as building blocks - [C++]
  • Protocols and Interfaces
  • 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...?

    | 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