Packages

ExCubecl is a GPU compute runtime for Elixir powered by CubeCL via Rust NIFs. Provides GPU buffer management, kernel execution, async command submission, and pipeline orchestration. Currently includes CPU fallback implementations.

Current section

Files

Jump to
ex_cubecl guides 09_audio_processing.md
Raw

guides/09_audio_processing.md

# Audio Processing Guide
Complete reference for audio processing operations in ExCubecl. Audio operations are implemented in the Rust NIF.
## AudioSamples Struct
```elixir
%ExCubecl.AudioSamples{
handle: #Reference<...>, # Rust NIF-managed CPU-side resource (f32 planar PCM)
channels: 2,
sample_rate: 48000,
frames: 1024, # samples per channel
pts: 0 # presentation timestamp (µs)
}
```
## Mixing
```elixir
# Simple mix (equal gain)
{:ok, mixed} = ExCubecl.Audio.mix([track_a, track_b])
# Mix with per-track gain
{:ok, mixed} = ExCubecl.Audio.mix([track_a, track_b], gains: [0.7, 0.5])
# Mix many tracks
{:ok, mixed} = ExCubecl.Audio.mix(
[dialogue, music, sfx],
gains: [1.0, 0.3, 0.6]
)
```
The `pcm_mix` kernel is implemented in the NIF.
## Overlay with Ducking
```elixir
# Overlay foreground on background, ducking background by 12dB
{:ok, mixed} = ExCubecl.Audio.overlay(bg, fg, duck_level: -12)
# Custom duck level
{:ok, mixed} = ExCubecl.Audio.overlay(bg, fg, duck_level: -6)
```
## Resampling
```elixir
# 44.1kHz → 48kHz
{:ok, resampled} = ExCubecl.Audio.resample(samples, from: 44100, to: 48000)
# 48kHz → 44.1kHz
{:ok, resampled} = ExCubecl.Audio.resample(samples, from: 48000, to: 44100)
```
Uses linear interpolation in the current implementation. For higher quality, use the
`biquad_filter` API.
## Channel Conversion
```elixir
# Stereo → Mono (downmix)
{:ok, mono} = ExCubecl.Audio.channels(samples, :stereo, :mono)
# Mono → Stereo (upmix)
{:ok, stereo} = ExCubecl.Audio.channels(mono_samples, :mono, :stereo)
# Supported layouts: :mono, :stereo, :surround_51, :surround_71
```
## Audio Filters
```elixir
# EQ (via biquad filter)
{:ok, eq'd} = ExCubecl.Filter.apply(samples, :eq,
bands: [{:high_pass, 80}, {:shelf_high, 8000, 3.0}])
# Compressor
{:ok, compressed} = ExCubecl.Filter.apply(samples, :compressor,
threshold: -18, ratio: 4.0)
# Reverb (FFT convolution)
{:ok, reverbed} = ExCubecl.Filter.apply(samples, :reverb,
room_size: 0.5, wet: 0.2)
# Normalize
{:ok, normalized} = ExCubecl.Filter.apply(samples, :normalize)
```
## Audio Filter Chains
```elixir
{:ok, result} = ExCubecl.Filter.chain(samples, [
{:eq, [bands: [{:high_pass, 80}]]},
{:compressor, [threshold: -18, ratio: 4.0]},
{:normalize, []}
])
```
Pipeline integration example using NIF-backed operations:
```elixir
{:ok, track_a} = ExCubecl.AudioSamples.from_map(audio_map_a)
{:ok, track_b} = ExCubecl.AudioSamples.from_map(audio_map_b)
{:ok, mixed} = ExCubecl.buffer(List.duplicate(0.0, 1024 * 2), [1024 * 2], :f32)
{:ok, filtered} = ExCubecl.buffer(List.duplicate(0.0, 1024 * 2), [1024 * 2], :f32)
{:ok, output} = ExCubecl.buffer(List.duplicate(0.0, 1024 * 2), [1024 * 2], :f32)
{:ok, pipeline} = ExCubecl.pipeline()
:ok = ExCubecl.pipeline_add(pipeline, "pcm_mix", [track_a.handle, track_b.handle], mixed, %{gains: [0.7, 0.5]})
:ok = ExCubecl.pipeline_add(pipeline, "biquad_filter", [mixed], filtered, %{high_pass: 80})
{:ok, _cmd_ids} = ExCubecl.pipeline_run(pipeline)
:ok = ExCubecl.pipeline_free(pipeline)
```