Embedding libecasound in C++ Applications

Yes, C++ applications can directly embed libecasound without spawning or interacting with an external Ecasound process. Ecasound is architected with a strict separation between its processing engine and user interfaces, exposing its core multitrack audio processing capabilities as a shared C++ library. By linking directly against libecasound or its C-language binding libecasoundc, developers can initialize, configure, and control the entire audio processing chain within the same memory space and process thread hierarchy as their main application.

The Architecture Behind libecasound

The standalone ecasound executable is essentially an interface wrapper around the core processing framework. All routing, effects processing, multitrack recording, and playback capabilities exist natively inside libecasound.

When integrating Ecasound into a C++ project, you do not need to rely on external process management, standard I/O redirection, or local socket communication. Instead, your binary links directly to the engine, providing:

Integration Options: Native C++ vs. C Bindings

Developers have two primary methods for embedding the library:

  1. Native C++ Control Interface (ECA_CONTROL_INTERFACE): Included via <libecasound/eca-control-interface.h>, this class allows native C++ code to instantiate the Ecasound engine directly. Commands are issued programmatically using standard string-based ECI (Ecasound Control Interface) commands, maintaining full access to the underlying engine objects.
  2. Plain C Interface (libecasoundc): This is a procedural wrapper around the C++ engine. It can be easily used in C++ code using #include <libecasoundc/ecasoundc.h> and provides functions such as eci_init(), eci_command(), and eci_cleanup().

Implementation Workflow

Embedding libecasound involves three core steps:

1. Linking the Library

Your build system (such as CMake, Make, or Meson) must locate and link against libecasound. Using pkg-config, compile and link flags can be retrieved via:

pkg-config --cflags --libs libecasound

Alternatively, direct linker flags such as -lecasound (or -lecasoundc) should be added to your compiler invocation.

2. Instantiating the Control Interface

Using the native C++ class, you instantiate ECA_CONTROL_INTERFACE to manage the audio session:

#include <libecasound/eca-control-interface.h>
#include <iostream>

int main() {
    // Instantiate the engine directly within the C++ process
    ECA_CONTROL_INTERFACE eci;

    // Issue setup commands
    eci.command("cs-add my_session");
    eci.command("c-add my_chain");
    eci.command("ai-add input.wav");
    eci.command("ao-add default"); // Route to system output (e.g., ALSA/JACK)

    // Start processing
    eci.command("start");

    // Engine runs within the application context
    while (!eci.command_float_arg("engine-status")) {
        // Application loop or sleep
    }

    eci.command("stop");
    return 0;
}

3. Managing Engine State and Real-Time Threads

Once initialized, libecasound spawns internal real-time processing threads according to the selected audio subsystem (such as ALSA, JACK, or OSS). The hosting C++ application maintains control via the instanced interface object, with real-time audio threads running concurrently within the application's process space.

Key Considerations