NET OwnaudioNET API Reference

High-level audio API with professional features including multi-track mixing, effects processing, synchronization, and real-time audio manipulation.

Production-Ready Features OwnaudioNET provides 15+ professional effects, unlimited track mixing, Master Clock synchronization, tempo/pitch control, and recording capabilities.

Overview

OwnaudioNET extends Ownaudio.Core with high-level features:

Initialization

OwnaudioNet Class

Central initialization and configuration for OwnaudioNET.

⚠️ UI APPLICATIONS: Use Async API For desktop/mobile UI applications, use async methods to prevent UI thread blocking:
  • await InitializeAsync() - Prevents 50-5000ms UI freeze
  • await StopAsync() - Prevents up to 2000ms UI freeze
  • await ShutdownAsync() - Non-blocking shutdown
  • await GetOutputDevicesAsync() - Non-blocking device enumeration
Synchronous Initialization (Console Apps)
// Default initialization (48kHz, stereo, 512 frames)
OwnaudioNet.Initialize();

// Custom configuration
var config = new AudioConfig
{
    SampleRate = 44100,
    Channels = 2,
    BufferSize = 256
};
OwnaudioNet.Initialize(config);

// Shutdown
OwnaudioNet.Shutdown();
Async Initialization (UI Apps) ⭐ RECOMMENDED
// Default async initialization
await OwnaudioNet.InitializeAsync();

// Custom async configuration
var config = new AudioConfig
{
    SampleRate = 44100,
    Channels = 2,
    BufferSize = 256
};
await OwnaudioNet.InitializeAsync(config);

// Async device enumeration
var devices = await OwnaudioNet.GetOutputDevicesAsync();
foreach (var device in devices)
{
    Console.WriteLine($"Device: {device.Name}");
}

// Async shutdown
await OwnaudioNet.ShutdownAsync();
Method Description Recommended For
Initialize() Initialize with default settings (⚠️ BLOCKS 50-200ms) Console apps
Initialize(AudioConfig) Initialize with custom config (⚠️ BLOCKS 50-5000ms) Console apps
InitializeAsync() ✅ Async init with default settings (NON-BLOCKING) UI apps (WPF, MAUI, Avalonia)
InitializeAsync(AudioConfig) ✅ Async init with custom config (NON-BLOCKING) UI apps (WPF, MAUI, Avalonia)
Shutdown() Shutdown and release resources (⚠️ BLOCKS up to 2000ms) Console apps
ShutdownAsync() ✅ Async shutdown (NON-BLOCKING) UI apps (WPF, MAUI, Avalonia)

Channel Routing

Channel routing lets you direct audio to specific physical output channels on a multi-output device (USB interfaces, ASIO cards, monitor controllers, etc.). Set OutputChannelSelectors in your AudioConfig to select which physical channels to use. This works with all engines and platforms — not just ASIO.

🔀 Cross-Engine Support
  • PortAudio + ASIO: Native hardware channel selection (zero overhead)
  • PortAudio + WASAPI / CoreAudio / ALSA: Software routing in the audio callback
  • MiniAudio (default engine): Software routing in the audio callback

Configuration

Set the number of logical Channels equal to the number of selectors. Each entry in OutputChannelSelectors is a 0-based physical channel index.

Basic Output Channel Routing
// Route stereo output to the second pair of outputs (ch 4 and 5)
// on an 8-channel USB interface
var config = new AudioConfig
{
    SampleRate = 48000,
    Channels   = 2,                              // 2 logical channels
    OutputChannelSelectors = new[] { 4, 5 }      // physical ch 4 and 5
};

await OwnaudioNet.InitializeAsync(config);
OwnaudioNet.Start();

// AudioMixer and FileSource work normally - routing is transparent
var engine = OwnaudioNet.Engine!.UnderlyingEngine;
var mixer  = new AudioMixer(engine, bufferSizeInFrames: 512);
var music  = new FileSource("music.wav", 8192,
    targetSampleRate: 48000, targetChannels: 2);

mixer.AddSource(music);
mixer.Start();
music.Play();

How Channel Assignment Works in the Mixer

The AudioMixer sums all sources per logical channel into a single N-channel buffer, then hands that buffer to the engine. The engine applies the OutputChannelSelectors routing to map each logical channel to its physical counterpart.

Every BaseAudioSource subclass — FileSource, SampleSource, InputSource, and custom sources — exposes an OutputChannelMapping property and a fluent RouteToChannels() helper. When set, the mixer automatically places that source's audio into the specified logical channel slots and leaves all other slots silent, so multiple sources can play on distinct physical channels without a custom IAudioSource implementation.

Scenario Result
Sources share the same logical channel count, no OutputChannelMapping set All sources play on the same physical channels – mixed together
Each source has its own OutputChannelMapping / RouteToChannels() Each source is heard on its own dedicated physical channels

Case 1 – All Sources on the Same Physical Channels (Default)

With a standard 2-channel config and OutputChannelSelectors = [4, 5], every source added to the mixer plays on physical channels 4 and 5. This is the simplest and most common use case.

All Sources → Physical Ch 4 and 5
var config = new AudioConfig
{
    Channels               = 2,
    OutputChannelSelectors = new[] { 4, 5 }  // physical ch 4 and 5
};
await OwnaudioNet.InitializeAsync(config);
OwnaudioNet.Start();

var engine    = OwnaudioNet.Engine!.UnderlyingEngine;
var mixer     = new AudioMixer(engine, bufferSizeInFrames: 512);

// Both sources will play on physical ch 4 and 5 (mixed together)
var music     = new FileSource("music.wav",  8192, targetSampleRate: 48000, targetChannels: 2);
var metronome = new FileSource("click.wav",  8192, targetSampleRate: 48000, targetChannels: 2);

mixer.AddSource(music);
mixer.AddSource(metronome);
mixer.Start();
music.Play();
metronome.Play();

Case 2 – Sources on Separate Physical Channels

To send each source to a different pair of physical channels, call RouteToChannels() on each source. The mixer automatically routes that source's stereo audio into the specified logical channel slots and zeroes out the rest.

Per-Source Routing with RouteToChannels()
// 8-channel interface: music on physical ch 0+1, metronome on physical ch 4+5
// AudioConfig uses 4 logical channels mapped to physical 0, 1, 4, 5
var config = new AudioConfig
{
    Channels               = 4,
    OutputChannelSelectors = new[] { 0, 1, 4, 5 }
};
await OwnaudioNet.InitializeAsync(config);
OwnaudioNet.Start();

var engine    = OwnaudioNet.Engine!.UnderlyingEngine;
var mixer     = new AudioMixer(engine, bufferSizeInFrames: 512);

var music     = new FileSource("music.wav",  8192, targetSampleRate: 48000, targetChannels: 2);
var metronome = new FileSource("click.wav",  8192, targetSampleRate: 48000, targetChannels: 2);

// Route each source to its own logical channel pair.
// The engine then maps logical → physical via OutputChannelSelectors:
//   logical 0+1 → physical 0+1  (music)
//   logical 2+3 → physical 4+5  (metronome)
music.RouteToChannels(0, 1);
metronome.RouteToChannels(2, 3);

mixer.AddSource(music);
mixer.AddSource(metronome);
mixer.Start();
music.Play();
metronome.Play();

RouteToChannels() and OutputChannelMapping are available on all BaseAudioSource subclasses: FileSource, SampleSource, InputSource, and any custom subclass. The mapping array length must equal the source's Config.Channels.

⚠️ Channel Count Rule The OutputChannelSelectors array length must equal the Channels value. Use AudioConfig.Validate() to verify before initializing. Negative selector indices are also invalid.

Audio Sources

FileSource

File-based audio source with decoding, SoundTouch support, and Master Clock synchronization.

FileSource Usage
// Create from file
var source = new FileSource("music.mp3");

// Configure playback
source.Volume = 0.8f;          // Volume (0.0-1.0)
source.Loop = true;             // Enable looping
source.Tempo = 1.2f;            // 20% faster (0.8-1.2)
source.PitchShift = -2.0f;      // 2 semitones lower (-12..+12)

// Control playback
source.Play();
source.Pause();
source.Stop();
source.Seek(30.0);  // Seek to 30 seconds

// Get info
double position = source.Position;  // Current position (seconds)
double duration = source.Duration;  // Total duration (seconds)
AudioState state = source.State;    // Playing/Paused/Stopped

// Cleanup
source.Dispose();

Properties

Property Type Description
Id Guid Unique source identifier
State AudioState Current playback state
Volume float Volume level (0.0-1.0)
Loop bool Enable/disable looping
Position double Current position in seconds
Duration double Total duration in seconds
Tempo float Playback tempo (0.8-1.2, 1.0 = normal)
PitchShift float Pitch shift in semitones (-12..+12)
StartOffset double Timeline start position (for Master Clock sync)
OutputChannelMapping int[]? Logical mix-buffer channel indices this source writes into. Length must equal Config.Channels. null = write to all channels (default). Also available on SampleSource and InputSource.
RouteToChannels(params int[]) BaseAudioSource Fluent helper that sets OutputChannelMapping and returns this. Example: source.RouteToChannels(2, 3).

SampleSource

Play audio from memory samples with optional dynamic updates.

SampleSource Usage
// Generate or load samples
float[] samples = GenerateAudioSamples();

// Create source from existing samples
var config = new AudioConfig
{
    SampleRate = 48000,
    Channels = 2
};
var source = new SampleSource(samples, config);

// OR create empty source for dynamic updates
var dynamicSource = new SampleSource(
    bufferSizeInFrames: 48000,  // 1 second buffer
    config: config
);

// Update samples dynamically
float[] newSamples = GenerateNewSamples();
dynamicSource.SubmitSamples(newSamples);

// Playback control
source.Play();
source.Loop = true;

InputSource

Real-time audio input from microphone or line-in.

InputSource Usage
// Initialize OwnaudioNET (engine must be running)
OwnaudioNet.Initialize();

// Create input source
var input = new InputSource(
    engine: OwnaudioNet.Engine,
    bufferSizeInFrames: 8192  // Optional, default is 8192
);

// Add to mixer and start
mixer.AddSource(input);
input.Play();

SourceWithEffects

Wrapper for applying effects chains to any audio source.

SourceWithEffects Usage
var source = new FileSource("guitar.wav");

// Create source with effects wrapper
var sourceWithFx = new SourceWithEffects(source);

// Add effects to the chain
var reverb = new ReverbEffect
{
    Mix = 0.3f,
    RoomSize = 0.7f,
    Damping = 0.5f
};
sourceWithFx.AddEffect(reverb);

var compressor = new CompressorEffect(
    threshold: 0.5f,
    ratio: 4.0f,
    attackTime: 10.0f,
    releaseTime: 100.0f,
    makeupGain: 1.0f,
    sampleRate: 48000f
);
sourceWithFx.AddEffect(compressor);

// Modify effects dynamically
reverb.Enabled = false;  // Bypass effect
sourceWithFx.RemoveEffect(compressor);
sourceWithFx.ClearEffects();

AudioMixer

Central mixing engine for multi-track audio playback with Master Clock synchronization.

AudioMixer Usage
// Create mixer
var mixer = new AudioMixer(OwnaudioNet.Engine);
mixer.Start();

// Add sources
var drums = new FileSource("drums.wav");
var bass = new FileSource("bass.wav");
var guitar = new FileSource("guitar.wav");

mixer.AddSource(drums);
mixer.AddSource(bass);
mixer.AddSource(guitar);

// Control individual sources
drums.Volume = 0.8f;
bass.Volume = 0.7f;
guitar.Volume = 0.6f;

// Play sources
drums.Play();
bass.Play();
guitar.Play();

// Master controls
mixer.MasterVolume = 0.9f;

// Real-time metering
float leftPeak = mixer.LeftPeak;
float rightPeak = mixer.RightPeak;

// Recording
mixer.StartRecording("output.wav");
// ... playback ...
mixer.StopRecording();

// Cleanup
mixer.Stop();
mixer.Dispose();

Properties

Property Type Description
MasterVolume float Master volume level (0.0-1.0)
IsRunning bool True if mixer is running
SourceCount int Number of active sources
LeftPeak float Left channel peak level
RightPeak float Right channel peak level
IsRecording bool True if currently recording
MasterClock MasterClock Master clock for timeline synchronization

Methods

Method Description
Start() Start the mixer
Stop() Stop the mixer
AddSource(IAudioSource) Add audio source to mixer
RemoveSource(Guid) Remove source by ID
RemoveAllSources() Remove all sources
AddMasterEffect(IEffectProcessor) Add effect to master chain
RemoveMasterEffect(IEffectProcessor) Remove effect from master chain
StartRecording(string) Start recording to WAV file
StopRecording() Stop recording

Audio Effects

OwnaudioNET includes 15+ professional audio effects with preset support.

Complete Effects Documentation For detailed information about all effects, parameters, presets, and usage examples, see the dedicated Audio Effects Reference.

Quick Start - Adding Effects

Basic Effect Usage
// Create source and wrap with effects capability
var fileSource = new FileSource("audio.mp3");
var source = new SourceWithEffects(fileSource);

// Add effects
var compressor = new CompressorEffect(CompressorPreset.VocalGentle);
var reverb = new ReverbEffect(ReverbPreset.VocalBooth);
var limiter = new LimiterEffect(48000f, LimiterPreset.Mastering);

source.AddEffect(compressor);
source.AddEffect(reverb);
source.AddEffect(limiter);

// Control effects
reverb.Enabled = false;  // Bypass
compressor.Threshold = 0.6f;  // Adjust parameter

// Add to mixer
mixer.AddSource(source);
mixer.Start();

Available Effects

Category Effects
Dynamics Compressor, Limiter, AutoGain, DynamicAmp
Frequency Equalizer (10-band), Equalizer30Band, Enhancer
Modulation Chorus, Flanger, Phaser, Rotary
Spatial Reverb, Delay
Distortion Distortion, Overdrive

See Also: Full Effects Documentation for detailed parameters, all presets, technical details, and advanced usage examples.

Synchronization

Master Clock Architecture

OwnaudioNET uses a professional DAW-style Master Clock for sample-accurate synchronization with timeline positioning and automatic drift correction.

Master Clock System (v2.4.0+) Timeline-based synchronization provides sample-accurate sync, start offsets, realtime/offline rendering modes, and automatic drift correction.
Master Clock Synchronization
// Create sources
var drums = new FileSource("drums.wav");
var bass = new FileSource("bass.wav");
var guitar = new FileSource("guitar.wav");

// Add to mixer
mixer.AddSource(drums);
mixer.AddSource(bass);
mixer.AddSource(guitar);

// Attach sources to Master Clock
drums.AttachToClock(mixer.MasterClock);
bass.AttachToClock(mixer.MasterClock);
guitar.AttachToClock(mixer.MasterClock);

// Optional: Set start offsets (timeline positioning)
drums.StartOffset = 0.0;    // Starts at 0 seconds
bass.StartOffset = 0.0;     // Starts at 0 seconds
guitar.StartOffset = 2.0;   // Starts at 2 seconds (delayed)

// Start mixer
mixer.Start();

// Start all sources for playback (IMPORTANT!)
drums.Play();
bass.Play();
guitar.Play();

// All attached sources now play in perfect sync with Master Clock

// Timeline control
mixer.MasterClock.SeekTo(10.0);  // Seek all tracks to 10 seconds

// Get current timeline position
double currentTime = mixer.MasterClock.CurrentTimestamp;
long samplePosition = mixer.MasterClock.CurrentSamplePosition;

// Rendering modes
mixer.MasterClock.Mode = ClockMode.Realtime;  // Default: dropout → silence + event
mixer.MasterClock.Mode = ClockMode.Offline;   // Offline: blocking, deterministic

Automatic Drift Correction

The Master Clock automatically maintains perfect synchronization with sub-10ms drift tolerance.

Drift Correction
// Drift correction is automatic with Master Clock
// Tolerance: 10ms (~480 samples @ 48kHz)
// When drift exceeds tolerance, sources automatically resync

// Monitor dropout events (occurs when sources can't keep up)
mixer.TrackDropout += (sender, e) =>
{
    Console.WriteLine($"Track dropout: {e.TrackName}");
    Console.WriteLine($"  At time: {e.MasterTimestamp:F3}s");
    Console.WriteLine($"  Missed frames: {e.MissedFrames}");
    Console.WriteLine($"  Reason: {e.Reason}");
};

Timeline Features

Timeline and Start Offsets
// DAW-style timeline positioning
var intro = new FileSource("intro.wav");
var verse = new FileSource("verse.wav");
var chorus = new FileSource("chorus.wav");

intro.AttachToClock(mixer.MasterClock);
verse.AttachToClock(mixer.MasterClock);
chorus.AttachToClock(mixer.MasterClock);

// Position tracks on timeline
intro.StartOffset = 0.0;      // 0:00
verse.StartOffset = 8.5;      // 0:08.5
chorus.StartOffset = 24.3;    // 0:24.3

mixer.AddSource(intro);
mixer.AddSource(verse);
mixer.AddSource(chorus);

mixer.Start();

// Start all sources
intro.Play();
verse.Play();
chorus.Play();

// Tracks play at their scheduled times based on StartOffset

// Timeline navigation
mixer.MasterClock.SeekTo(20.0);  // Jump to 20 seconds - all tracks sync

Related Documentation