Accessing Ecasound Audio Sample Buffers in C++
Direct access to internal audio sample buffers in Ecasound is
achieved by working directly with the core C++ multimedia classes rather
than the high-level control interfaces. By extending the
CHAIN_OPERATOR or AUDIO_IO base classes,
developers can intercept the signal graph and manipulate Ecasound’s
internal SAMPLE_BUFFER objects. This architecture grants
real-time access to raw audio sample arrays represented as native
floating-point pointers, bypassing the IPC overhead of the standard
Ecasound Control Interface (ECA-CI).
The SAMPLE_BUFFER
Architecture
At the heart of Ecasound’s internal processing is the
SAMPLE_BUFFER class. Ecasound processes audio in discrete
chunks determined by the engine's buffer size. Within
SAMPLE_BUFFER, audio is represented using the internal
sample_t type, which is typically a 32-bit single-precision
float (float) or 64-bit double depending on compilation
flags.
Rather than exposing raw global memory, SAMPLE_BUFFER
manages multi-channel audio data either as interleaved or
non-interleaved channel vectors. To retrieve the memory location of raw
samples:
- The method
channel_data(int channel)returns a direct pointer of typesample_t*to the beginning of the memory block for the specified audio channel. - The method
number_of_samples()provides the current frame count stored within the buffer. - The method
number_of_channels()defines the channel layout width.
Implementing
Direct Access via CHAIN_OPERATOR
The primary mechanism to inspect or modify buffers directly is to
implement a custom plugin by subclassing CHAIN_OPERATOR.
Chain operators are execution units inserted into Ecasound signal
chains.
- Subclassing: A C++ class inherits from
CHAIN_OPERATOR(defined inlibcasound). - Overriding
process(): The engine invokes the operator’sprocess()method on every iteration of the processing loop. - Retrieving the Buffer: Inside
process(), the operator accesses the chain's active buffer via the protected member pointerchain_bufferor by receiving a direct reference to the currentSAMPLE_BUFFER. - Pointer Arithmetic: The developer calls
chain_buffer->channel_data(ch)to acquire the underlyingsample_t*pointer for each active channel. From there, standard pointer operations or SIMD vector instructions can be used directly on the audio frames.
Implementing
Custom Audio Sources or Sinks via AUDIO_IO
For stream endpoints that generate or consume audio directly from
memory, the AUDIO_IO base class is used. Inheriting from
AUDIO_IO allows developers to bypass disk or ALSA/JACK
subsystems:
- Custom input objects override the
read_buffer(SAMPLE_BUFFER *buf)function, where they write directly into the memory locations obtained frombuf->channel_data(). - Custom output objects override the
write_buffer(SAMPLE_BUFFER *buf)function, reading directly from thesample_t*pointers into user-defined memory or custom network pipelines.
Concurrency and Performance Implications
Ecasound’s direct C++ API executes custom CHAIN_OPERATOR
and AUDIO_IO code directly inside the audio engine’s
real-time execution thread. Direct pointer access to
SAMPLE_BUFFER memory eliminates dynamic allocation and data
copying between buffers. However, because operations run synchronously
within the real-time loop, any code accessing these raw buffers must
remain deterministic, non-blocking, and free of system calls that could
trigger buffer underruns or dropouts.