How Ecasound Manages LADSPA Plugin Memory

Ecasound manages memory for active LADSPA (Linux Audio Developer's Simple Plugin API) plugins by enforcing a strict separation between setup time and real-time processing. When integrating LADSPA plugins into an audio processing chain, Ecasound orchestrates memory management across two primary domains: the plugin's internal private state, which the plugin allocates itself during instantiation, and the external audio and control buffers, which Ecasound pre-allocates and assigns prior to playback. By handling all dynamic memory allocations during the graph configuration stage, Ecasound guarantees zero dynamic memory allocation or deallocation during the real-time processing loop.

Instantiation and Internal Memory

When a LADSPA effect is added to an Ecasound chain, Ecasound locates the shared library object (.so) using the dynamic linker (dlopen). Once the plugin descriptor is retrieved, Ecasound initiates the memory lifecycle of the plugin instance:

  1. Calling instantiate(): Ecasound calls the plugin descriptor's instantiate() function, passing the target sample rate.
  2. Plugin Heap Allocation: The plugin itself allocates whatever private instance data it requires (such as delay lines, filter states, or operational variables) using standard system allocators (malloc, calloc, or C++ new).
  3. Handle Management: The plugin returns an opaque LADSPA_Handle representing that instance's memory space. Ecasound stores this pointer within its internal chain-operator wrapper objects.

Buffer Management and Port Connection

LADSPA plugins do not allocate memory for their input and output audio channels; the host is entirely responsible for audio data storage.

  • Pre-allocation: During engine initialization and chain compilation, Ecasound pre-allocates fixed-size audio buffers (sized according to Ecasound's configured buffer size) and float variables for control ports.
  • Port Binding: Ecasound calls the plugin’s connect_port() function for every defined audio and control port. It passes memory addresses directly pointing to its internal audio buffers or control value addresses.
  • Shared Memory Usage: If multiple operators or chains interact, Ecasound passes the appropriate pointers through the signal path, avoiding unnecessary buffer copying whenever possible.

Real-Time Execution Safety

Once Ecasound switches into active audio processing mode:

  • Zero Dynamic Allocation: Neither Ecasound nor the LADSPA plugin is permitted to allocate or deallocate memory. Calling memory functions like malloc(), realloc(), or free() can trigger locks, system calls, or page faults that lead to audio dropouts (xruns).
  • Buffer Processing: The processing thread repeatedly invokes the plugin's run() function, operating strictly within the memory addresses previously assigned during connect_port().
  • State Activation: Prior to running, Ecasound calls the plugin’s activate() function (if defined), allowing the plugin to reset internal states (such as zeroing out delay buffers) without reallocating memory.

Instance Destruction and Deallocation

When an audio engine stops, a chain is modified, or Ecasound exits, the memory deallocation phase executes in reverse order of initialization:

  1. Deactivation: Ecasound invokes the plugin’s deactivate() callback (if present), signaling that real-time processing has finished.
  2. Instance Cleanup: Ecasound calls the plugin's cleanup() function, passing the instance handle. The plugin executes its destructor logic, releasing all internal heap memory via free() or delete.
  3. Host Buffer Release: Ecasound deallocates its own internal audio buffers, parameter trackers, and wrapper structures.
  4. Library Unloading: If no other active instances depend on the loaded shared library, Ecasound closes the library handle via dlclose(), releasing the plugin's code segment from process memory.