Skip to content

Releases: ModernMube/OwnAudioSharp

OwnAudioSharp v3.1.7

Choose a tag to compare

@ModernMube ModernMube released this 23 Jun 17:33
e358b5c

What's New

This release rolls up the changes since v3.1.3, with a focus on more accurate analysis, lower GC pressure, and synchronization correctness.

BPM Detection — Rewritten

BpmDetect was rebuilt around normalised autocorrelation with a perceptual tempo prior, producing markedly more accurate tempo estimates across genres and avoiding the common octave-error (half/double-tempo) mistakes.

Chord Detection — GC-Free & AOT-Safe

The chord detection pipeline was rewritten to be allocation-free on the hot path and fully AOT-compatible, making it safe for trimmed/Native AOT deployments and real-time use without GC pauses.

AudioMixer — Dynamic Configuration

The AudioMixer now supports dynamic (re)configuration of its output format and source set, with a more robust shutdown path (correct thread join on stop).

Fixes

  • FileSource Position double-tempo regressionPosition advanced by framesRead × tempo / sampleRate instead of wall-clock time. SoundTouch already applies the tempo conversion, so the extra factor double-counted it (regressing the v2.6.7 fix). Position now tracks wall-clock time in both standalone and synchronized read paths.
  • OutputDeviceId initialization — correct default device id on startup.
  • AudioDeviceInfo.DefaultSampleRate — accurate reported sample rate.
  • FileSource synchronization — additional drift-correction fixes.

Notes

  • Reminder: in the native engine, managed code never touches raw audio data directly.
  • VocalRemover is moving to a separate package (see README).

Full Changelog: V3.1.3...V3.1.7

Packages (NuGet)

Package Version
OwnAudioSharp 3.1.7
OwnAudioSharp.Basic 3.1.7
OwnAudioSharp.Mobile 3.1.7

OwnAudioSharp v3.1.3

Choose a tag to compare

@ModernMube ModernMube released this 14 Jun 12:24

What's New

Adaptive Synchronization Tolerance

The MasterClock sync engine now automatically adjusts its drift correction thresholds based on real-time hardware performance — no configuration needed. On capable hardware the tightest possible tolerances are active; on slower systems the engine relaxes them to prevent constant red-zone corrections.

AdaptiveScale Green Zone Yellow Zone Meaning
1.0 5 ms 25 ms Optimal — strict defaults active
2.0 10 ms 50 ms Moderate load — tolerances doubled
4.0 20 ms 100 ms High load — fully relaxed

The scale increases by 0.5 steps when ≥ 5 red-zone hits occur within a 3-second window, and decreases by 0.5 steps after 8 consecutive seconds in the green zone.

Tighter Default Tolerances

Threshold Previous New
SyncTolerance (Green Zone) 20 ms 5 ms
SoftSyncTolerance (Yellow Zone) 100 ms 25 ms

SyncDiagnostics — Runtime Health Check

A new SyncDiagnostics property on FileSource exposes the current adaptive state as a zero-allocation readonly struct. Use it to detect whether the adaptive system has elevated its thresholds, which may indicate a performance issue in a custom effect or processing pipeline.

SyncDiagnosticsSnapshot diag = fileSource.SyncDiagnostics;

if (diag.IsRelaxed)
{
    Console.WriteLine($"Adaptive tolerance active — Scale: {diag.AdaptiveScale:F1}x");
    Console.WriteLine($"Green zone:  {diag.EffectiveSyncToleranceMs:F1} ms  (baseline: 5 ms)");
    Console.WriteLine($"Yellow zone: {diag.EffectiveSoftSyncToleranceMs:F1} ms (baseline: 25 ms)");
    Console.WriteLine($"Red zone hits in window: {diag.RedZoneHitsInWindow}");
}

SyncDiagnosticsSnapshot is a readonly struct — zero heap allocation, AOT-compatible, safe to call from any thread.

WaveDisplayControl — Zoomed-In Line Rendering

When samplesPerPixel < 1.0 (zoomed in past individual samples), the waveform renderer now switches to a connected line style for a cleaner visual. Added SampleToPixel / PixelToSample inline helpers for coordinate conversion.


NuGet Packages

Package Version
OwnAudioSharp 3.1.3
OwnAudioSharp.Basic 3.1.3
OwnAudioSharp.Mobile 3.1.3

OwnAudioSharp v3.1.0

Choose a tag to compare

@ModernMube ModernMube released this 13 Jun 13:30

OwnAudioSharp v3.1.0 Release Notes

Release Date: June 2026 | Requirement: .NET 10.0+

New Features

Optional FFmpeg Decoder Integration

OwnAudioSharp now supports FFmpeg 8+ as an optional, zero-dependency decoder backend. FFmpeg is not bundled — if the system libraries are present they are detected and loaded automatically; if not, the built-in decoders continue to work unchanged. There are no breaking API changes.

  • FFmpegConfig class for specifying a custom library search path and querying availability at runtime
  • Supports all formats FFmpeg can decode (AAC, OGG, OPUS, M4A, WMA, and more) in addition to the built-in MP3 / WAV / FLAC decoders
  • AudioDecoderFactory selects FFmpeg automatically when available and the format is not handled natively
  • Full P/Invoke interop layer (FFmpegInterop) with source-generated [LibraryImport] — AOT-safe
// Optional: point to a non-standard FFmpeg location
FFmpegConfig.LibraryPath = "/opt/ffmpeg/lib";

// Check availability before use
if (FFmpegConfig.IsAvailable)
    Console.WriteLine("FFmpeg decoder active");

// No other changes — AudioDecoderFactory picks the right decoder automatically
using var decoder = AudioDecoderFactory.Create("audio.opus", 48000, 2);

MIDI API — Major Extension

SysEx Receive
IMidiInputPort now exposes a dedicated SysExReceived event that delivers complete 0xF0 … 0xF7 frames as a ReadOnlySpan<byte>. The event uses the custom SysExReceivedHandler delegate because Action<ReadOnlySpan<byte>> cannot be used as an event type directly. All platform implementations are zero-allocation in the hot path:

  • Windows (WinMM): four rotating 4 KB unmanaged MIDIHDR buffers managed by the driver callback
  • macOS (CoreMIDI): 64 KB per-port accumulation buffer that reassembles SysEx frames split across CoreMIDI packets
  • Linux (ALSA rawmidi): byte-level state machine with running-status and cross-read fragmentation support; [InlineArray(3)] struct for channel message assembly avoids heap allocation

Virtual MIDI Ports
MidiPortFactory.CreateVirtualInput(name) and CreateVirtualOutput(name) create software MIDI endpoints visible system-wide to other applications and DAWs. SysEx receive is fully supported on virtual ports.

  • macOS: MIDIDestinationCreate / MIDISourceCreate + MIDIReceived via CoreMIDI
  • Linux: ALSA Sequencer (snd_seq_t) — connectable via aconnect

Hot-Plug Device Monitoring
MidiPortFactory.PortsChanged fires when MIDI devices are connected or disconnected. Activate with StartMonitoring(), deactivate with StopMonitoring().

  • macOS: CoreMIDI client notification callback — zero polling, fully event-driven
  • Linux: FileSystemWatcher on /dev/snd via kernel inotify

Timestamped Send (macOS)
MacOsMidiOutputPort exposes a Send(in MidiMessage, long timestampNs) overload. CoreMIDI schedules the message at the exact Mach Absolute Time, eliminating OS scheduling jitter. Pass 0 for immediate delivery.

AudioEngineMidiClock
AudioEngineMidiClock derives 24 PPQN MIDI Timing Clock pulses directly from the audio render loop, eliminating OS scheduling jitter entirely. A fractional sample accumulator maintains pulse accuracy regardless of audio block size.

var audioClock = new AudioEngineMidiClock();
audioClock.UpdateTempo(bpm: 120.0, sampleRate: 48000);

// Call from your audio render callback on every block:
void OnAudioBlock(int blockSize) =>
    audioClock.ProcessAudioBlock(blockSize, outputPort);

Native Engine Improvements

  • MiniAudio bindings (MaBinding): comprehensive update covering device enumeration, callback delegates, and device-switch support — MiniAudio backend is now fully operational
  • PortAudio bindings (PaBinding): extended P/Invoke coverage and improved delegate management
  • LibraryLoader: more robust cross-platform shared library discovery and loading

Effects & Mixer Improvements

  • SourceWithEffects: new source wrapper that applies an IEffectProcessor chain directly on the decode path, before the sample reaches the mixer
  • IEffectProcessor interface updated with a unified Process(Span<float>) contract
  • VST3EffectProcessor: aligned to the updated interface
  • SmartMasterEffect / SmartMasterAudioChain: accuracy and stability improvements
  • AutoGainEffect, LimiterEffect: added to the built-in effect set
  • AudioMixer: significant refactor of the mix thread, source management, recording, and effect management partials for correctness under concurrent source add/remove

Bug Fixes

  • Stale audio on stop/restart: output and input ring buffers are now flushed when the engine is stopped, preventing leftover samples from a previous session playing back at the start of the next one (AudioEngineWrapper, NativeAudioEngine)
  • Mixer EoS seek restart: sources with a non-zero StartOffset or non-default Tempo are now seeked to the correct position when the mixer loops at end-of-stream
  • FileSource EoS seek restart: the internal decode buffer and SoundTouch state are cleared on end-of-stream seek, preventing processed audio from the previous cycle bleeding into the next playback pass

AOT & Performance

  • sizeof(T) replaces Marshal.SizeOf<T>() in all native call hot paths (WinMM MIDIHDR, ALSA Sequencer structs)
  • ArrayPool<byte>.Shared used for large SysEx payloads (>4 KB) on macOS; ≤4 KB paths use stackalloc
  • All new P/Invoke uses [LibraryImport] (source-generated, AOT-safe)
  • Platform selection is runtime via RuntimeInformation.IsOSPlatform — no compile-time #if required in application code

Tests

New MSTest project OwnAudio.MidiTest added:

  • MidiMessage construction and property correctness (24 tests)
  • SysExReceivedHandler delegate behaviour (4 tests)
  • AudioEngineMidiClock pulse timing and fractional accumulator (7 tests)
  • MidiClock thread-based clock (11 tests)
  • MidiPortFactory enumeration and monitoring API (7 tests)
  • Hot-plug monitoring lifecycle (5 tests)
  • Virtual port loopback (3 tests)

Packages

Package Version Description
OwnAudioSharp 3.1.0 Desktop (Windows, Linux, macOS) with AI/ML features
OwnAudioSharp.Basic 3.1.0 Desktop without AI/ML features
OwnAudioSharp.Mobile 3.1.0 Mobile (Android, iOS)
OwnAudioSharp.Midi 3.1.0 MIDI I/O, SysEx, Virtual Ports, Hot-Plug, File, Clock

OwnAudioSharp v3.0.14

Choose a tag to compare

@ModernMube ModernMube released this 04 Jun 19:22

OwnAudioSharp v3.0.14 Release Notes

Release Date: June 2026 | Requirement: .NET 10.0+

Performance

Input Engine: Zero-Allocation Recording Path
IAudioEngine.Receives was changed from out float[] to Span<float> destination, so the caller provides the buffer instead of the engine allocating a new array on every call. AudioEngineWrapper.Receive now rents from AudioBufferPool (which was previously unused on the input path), achieving true zero-allocation recording. This eliminates GC pressure in the audio capture hot path and prevents buffer underruns caused by GC stalls during active recording.

  • IAudioEngine: Receives(out float[])Receives(Span<float> destination)
  • NativeAudioEngine: reads directly into caller-provided span via LockFreeRingBuffer.Read
  • MockAudioEngine: fills caller span in-place, removes new float[] allocation
  • AudioEngineWrapper: rents buffer from AudioBufferPool, returns on error
  • All call sites updated to pre-allocate buffers

Bug Fixes

  • Compiler warnings resolved: CS8604 null-reference warnings, MVVMTK0039 async void RelayCommand, and MSTEST0032 always-true assertions all eliminated across examples and tests.

Packages

Package Version Description
OwnAudioSharp 3.0.14 Desktop (Windows, Linux, macOS) with AI/ML features
OwnAudioSharp.Basic 3.0.14 Desktop without AI/ML features
OwnAudioSharp.Mobile 3.0.14 Mobile (Android, iOS)

OwnAudioSharp v3.0.13

Choose a tag to compare

@ModernMube ModernMube released this 02 Jun 18:43

OwnAudioSharp v3.0.13 Release Notes

Release Date: June 2026 | Requirement: .NET 10.0+

Performance

WaveAvaloniaDisplay: Zero-Allocation Render Loop
The Render() method previously allocated a StreamGeometry object on every frame (up to 60 times per second). This triggered GC collections that caused brief UI thread stalls, which in turn starved the audio pump thread and produced buffer underruns during multi-track playback. The geometry path has been replaced with direct DrawingContext.DrawLine() calls against the existing pre-allocated _pointCache array — the hot render path is now fully allocation-free.

New Features

ChordDetection: Improved Accuracy
Chord recognition now uses weighted chromagram templates and relaxed matching thresholds, significantly reducing false negatives on complex chords. The weighted template approach better reflects the harmonic importance of each pitch class, improving accuracy for major, minor, and extended chords in noisy or live audio signals.

Bug Fixes

  • CircularBuffer.Write deferred-clear path: The return 0 statement was missing after the deferred-clear block in Write(), causing execution to fall through into the normal write path with a freshly-reset buffer. Samples written immediately after a Clear() could corrupt the buffer state.

Packages

Package Version Description
OwnAudioSharp 3.0.13 Desktop (Windows, Linux, macOS) with AI/ML features
OwnAudioSharp.Basic 3.0.13 Desktop without AI/ML features
OwnAudioSharp.Mobile 3.0.13 Mobile (Android, iOS)

OwnAudioSharp v3.0.11

Choose a tag to compare

@ModernMube ModernMube released this 01 Jun 16:43

OwnAudioSharp v3.0.11 Release Notes

Release Date: June 2026 | Requirement: .NET 10.0+

New Features

AudioMixer: Buffered Output via AudioEngineWrapper
A new AudioMixer.Create(AudioEngineWrapper) static factory routes mixer output through the wrapper's internal CircularBuffer, providing ~85 ms pre-buffer headroom at 48 kHz / 512 frames. This prevents audio starvation when mixing 10–20 sources with VST master effects applied. The direct AudioMixer(IAudioEngine) constructor remains available for low-latency single-source setups.

Configurable Buffer Multiplier
AudioEngineWrapper and all OwnaudioNet.Initialize / InitializeAsync overloads now accept an optional bufferMultiplier parameter (default: 8). Increase to 16 or 32 when running heavy DSP loads — each step doubles the circular-buffer headroom without changing the engine buffer size or latency floor.

Performance

SourceWithEffects: Lock-Free Effects Hot Path
Per-call lock acquisition in ReadSamples has been replaced with a cached-array + volatile dirty-flag pattern. This eliminates ~20 lock acquisitions per mix cycle when running 20+ sources, reducing CPU overhead under heavy load.

AudioMixer: Dead Memory Removed
_parallelMixBuffers and _parallelReadBuffers fields (one array per CPU core, allocated but never used since parallel mode was reverted for stability) have been removed, saving 64–128 KB per mixer instance.

Bug Fixes

  • FileSource / SoundTouch startup timeout: ShouldFillBuffer fill thresholds were inverted — the decoder stopped at 50% capacity while PreBuffer/Play waited for 75%, causing a 500 ms timeout on every Play() call when pitch or tempo was active. Thresholds are now correctly 75% (SoundTouch) / 50% (direct).
  • FileSource underrun volume: ApplyVolume was not called on partially-read frames when a buffer underrun occurred, so the valid audio before the silence-pad was not volume-adjusted.
  • CircularBuffer.Skip on ARM64: Thread.MemoryBarrier() was missing before Interlocked.Add, potentially allowing CPU reordering of the read-pointer update on ARM64 (Apple Silicon, Linux arm64). Now consistent with Write and Read.
  • MIDI SysEx on Linux: Replaces VLQ-based length parsing (SMF format) with proper raw MIDI byte-stream handling — scans for the 0xF7 end-of-exclusive byte, clears running status after SysEx, and fixes running-status tracking for data-only bytes.

Dependencies

  • Avalonia updated from 12.0.312.0.4
  • OwnAudioVst updated from 1.6.01.6.3
  • coverlet.collector updated from 10.0.010.0.1
  • Microsoft.NET.Test.Sdk updated from 18.5.118.6.0
  • FluentAssertions updated from 8.9.08.10.0

Documentation

  • Channel Routing: Extended upmix/downmix guidance in the API Sources section.
  • api-core: Documented bufferMultiplier in Initialize examples with a callout explaining when to increase it.
  • api-mixer: Added Heavy Load Setup section documenting AudioMixer.Create with CircularBuffer pre-buffering for 8+ sources or VST effects.

Packages

Package Version Description
OwnAudioSharp 3.0.11 Desktop (Windows, Linux, macOS) with AI/ML features
OwnAudioSharp.Basic 3.0.11 Desktop without AI/ML features
OwnAudioSharp.Mobile 3.0.11 Mobile (Android, iOS)
OwnAudioSharp.Midi 3.0.11 MIDI support

OwnAudioSharp v3.0.7

Choose a tag to compare

@ModernMube ModernMube released this 26 May 19:31

OwnAudioSharp v3.0.7 Release Notes

Release Date: May 2026 | Requirement: .NET 10.0+

New Features

VocalRemover: On-Demand ONNX Model Download
Embedded ONNX model files have been removed from the package. Models are now downloaded on demand at runtime, significantly reducing the NuGet package size. This makes initial package restore faster while still providing full vocal separation functionality when needed.

Bug Fixes

  • PortAudio buffer drift: suggestedLatency is now derived from BufferSize / SampleRate instead of a fixed value. This fixes buffer drift on Focusrite audio interfaces (and other devices) where the driver's latency expectation did not match the configured buffer size.

Dependencies

  • OwnAudioVst updated from 1.5.211.6.0
  • Avalonia updated to 12.0.3
  • Microsoft.ML.OnnxRuntime updated to 1.26.0

Packages

Package Version Description
OwnAudioSharp 3.0.7 Desktop (Windows, Linux, macOS) with AI/ML features
OwnAudioSharp.Basic 3.0.7 Desktop without AI/ML features
OwnAudioSharp.Mobile 3.0.7 Mobile (Android, iOS)
OwnAudioSharp.Midi 3.0.5 MIDI support

OwnAudioSharp v3.0.5

Choose a tag to compare

@ModernMube ModernMube released this 22 May 18:32

OwnAudioSharp v3.0.5 Release Notes

Release Date: May 2025 | Requirement: .NET 10.0+

Improvements

Reliable Native Assembly Loading
OwnaudioNet now registers the Ownaudio.Native assembly via [ModuleInitializer], ensuring the native backend is always loaded before any audio operation — eliminating silent failures when the assembly was not yet referenced at call time.

Mp3Decoder Error Clarity
Removed the dynamic type-loading fallback (Type.GetType / Activator.CreateInstance) from the platform MP3 decoder path. When the native assembly is missing, a clear, actionable error message is shown instead of a silent no-op.

MIDI: Runtime Platform Detection
MidiPortFactory and all port implementations now use RuntimeInformation.IsOSPlatform() at runtime instead of #if WINDOWS / MACOS / LINUX compile-time guards. This makes the MIDI layer compatible with AOT and single-binary publishing without platform-specific builds.

Bug Fixes

  • Linux MIDI device enumeration: GetInputPortNames / GetOutputPortNames previously returned /dev/midi* OSS paths that snd_rawmidi_open cannot open. Now parses /proc/asound/rawmidi for ALSA hw:C,D names with direction filtering, with fallback to /dev/snd/midiCxDy node parsing. MidiPortFactory resolves the friendly name to the correct hw path before opening.
  • MaDecoder default channel count: Passing 0 channels to the native decoder config now correctly defers channel selection to the native layer (previously hardcoded to 2, which could override the source file's channel layout).

Documentation

  • Overhauled documentation site with dedicated API reference pages (Sources, Mixer, Effects, MIDI, Network, Sync)
  • Shared CSS/JS moved to assets/ directory
  • README badges and links updated

OwnAudioSharp v3.0.3

Choose a tag to compare

@ModernMube ModernMube released this 17 May 13:14
de5b3de

OwnAudioSharp v3.0.3

Breaking release — .NET 10 required; package names changed; managed platform engines removed.


Breaking Changes

Native-Only Audio Backend

All managed platform engine implementations have been removed. NativeAudioEngine (backed by MiniAudio / PortAudio) is now the sole audio backend on every platform:

  • Removed: WasapiEngine, CoreAudioEngine, PulseAudioEngine, AAudioEngine
  • Removed: GhostTrackSource, IGhostTrackObserver, AudioSynchronizer, AudioMixer.Sync, FileSource.Legacy
  • AudioEngineFactory is now reflection-free — factory registration happens via [ModuleInitializer] in Ownaudio.Native

Existing code targeting IAudioEngine and the high-level OwnaudioNet API is unaffected.

.NET 10 Required

All projects have been migrated from net9.0 to net10.0.

BaseAudioSource.Volume Range Extended

The Volume property now clamps to [0.0, 20.0] (was [0.0, 1.0]), enabling amplification as well as attenuation.


What's New

Native AOT Compatibility

The entire library is now Native AOT and trimming safe (IsAotCompatible=true, IsTrimmable=true):

  • OwnAudioFft — pure managed Cooley-Tukey radix-2 DIT FFT replaces MathNet.Numerics; no reflection, no dynamic codegen
  • AudioEngineFactory and AudioDecoderFactory — registration via [ModuleInitializer] delegate pattern, no Assembly.GetTypes() loops
  • GetManifestResourceNames() loops replaced with explicit AOT-safe resource names
  • JsonSerializerContext added for SmartMaster preset serialization (IL2026/IL3050 clean)
  • LibraryLoader uses AppContext.BaseDirectory instead of Assembly.Location (IL3000 clean)
  • [UnmanagedFunctionPointer(Cdecl)] applied to all MiniAudio callbacks for correct NativeAOT reverse P/Invoke thunk generation
# Publish as Native AOT
dotnet publish -c Release -r win-x64 -p:PublishAot=true

New Package: OwnAudioSharp.Midi

A fully managed, AOT-compatible MIDI library that replaces the DryWetMidi dependency:

  • Platform-native MIDI I/O: WinMM (Windows), CoreMIDI (macOS), ALSA (Linux) via LibraryImport P/Invoke
  • IMidiPort / IMidiInputPort / IMidiOutputPort — common port interfaces
  • MidiFileReader / MidiFileWriter — pure C# Standard MIDI File parser with running-status compression
  • MidiClock — 24 PPQN hardware-accurate clock thread (ThreadPriority.Highest)
  • MidiMessage — zero-allocation value type
  • Zero reflection anywhere; IsAotCompatible=true
dotnet add package OwnAudioSharp.Midi --version 3.0.3
var port = MidiPortFactory.CreateOutput("My Synth");
port.Open();
port.Send(new MidiMessage(MidiMessageType.NoteOn, channel: 0, note: 60, velocity: 100));

OwnAudioFft — Bluestein (Chirp-Z) Algorithm

OwnAudioFft now handles arbitrary FFT sizes, not just powers of two:

  • Power-of-two sizes continue to use the fast Cooley-Tukey radix-2 DIT path
  • Non-power-of-two sizes (e.g. NFft=6144) use the Chirp-Z transform with internal power-of-two padding
  • Per-thread chirp tables are cached to minimise per-call allocation

ARM NEON SIMD — Apple Silicon Support

SimdAudioConverter now includes an ARM NEON (AdvSimd) path alongside the existing SSE4.1/SSE2 x86 paths, providing vectorised audio format conversion on M1/M2/M3 Macs and ARM64 Linux.


Hermite Resampling

AudioResampler has been upgraded from linear to 4-point cubic Hermite (Catmull-Rom) interpolation:

  • Significantly reduced aliasing artefacts near Nyquist
  • Fixes negative _position clamp bug that caused sample-rate drift under certain conditions

VST3 State Restoration

VST3EffectProcessor gains two new methods for non-realtime project state restoration:

  • SetParametersSync(IEnumerable<(int id, double value)>) — applies multiple parameters synchronously on the plugin thread; unlike the SPSC-queue SetParameter, this updates native controller state immediately without requiring a processAudio drain cycle
  • Suitable for loading saved plugin states when reopening a project

New ReverbEffect Presets

Five new reverb presets with tuned room acoustics:

Preset Character
Spring Vintage spring tank
VocalBooth Tight, controlled room
DrumRoom Short, punchy reflections
Gated 80s-style gated reverb
Subtle Barely-there air

Bug Fixes

MiniAudio Channel Layout Mismatch (macOS / ARM)

MaResamplerConfig (managed, 64 bytes) was larger than ma_resampler_config in MiniAudio 0.11.x (48 bytes on arm64). Marshal.StructureToPtr was writing playback.channels and capture.channels at wrong native offsets — MiniAudio read channels=0 and defaulted to the hardware native channel count (mono mic instead of stereo).

PatchNativeDeviceConfig() now directly writes format and channel count at the verified native C offsets (playback.channels=124, capture.channels=164, confirmed by disassembly of ma_device_init). The patch is applied after every allocate_device_config call, including the fallback reinitialisation path.

Input Routing and Device Fallback

  • Fixed incorrect arithmetic in RouteInputChannels for physical input channels
  • Added pInput null-guard with one-time diagnostic logging
  • Retry device initialisation with system default devices when specific IDs fail (macOS duplex mode)
  • PortAudio → MiniAudio automatic fallback on negative error codes (macOS CoreAudio)
  • MA_MAX_DEVICE_NAME_LENGTH corrected to 255 (per miniaudio.h)

EnhancerEffect High-Pass Coefficient

The high-pass alpha coefficient was computed using the cutoff frequency instead of the sample-rate delta, producing incorrect filter behaviour at non-standard sample rates. The calculation now uses the correct Δ = 1 / (sampleRate × τ) formula.

Test Assembly Initialisation (macOS / Linux)

[AssemblyInitialize] now explicitly references typeof(NativeAudioEngine) to force the assembly load and its [ModuleInitializer] before any test runs. Without this, .NET's lazy assembly loading left AudioEngineFactory._creator null, causing all engine tests to fail with "No audio engine registered".


Dependency Updates

Package Old New
Avalonia 11.3.7 12.0.3
Microsoft.ML.OnnxRuntime 1.23.1 1.26.0
OwnAudioVst 1.4.5 1.5.20
DryWetMidi 8.0.2 removed (→ OwnAudioSharp.Midi)
MathNet.Numerics 5.0.0 removed (→ OwnAudioFft)
System.Numerics.Tensors 9.0.10 10.0.5

NuGet Packages

Package Platforms Version
OwnAudioSharp Windows / Linux / macOS (net10.0) 3.0.4
OwnAudioSharp.Mobile Android / iOS (net10.0-android, net10.0-ios) 3.0.3
OwnAudioSharp.Basic All platforms (net10.0) 3.0.3
OwnAudioSharp.Midi All platforms (net10.0) 3.0.4
dotnet add package OwnAudioSharp  --version 3.0.4
dotnet add package OwnAudioSharp.Mobile  --version 3.0.3
dotnet add package OwnAudioSharp.Basic   --version 3.0.3
dotnet add package OwnAudioSharp.Midi    --version 3.0.4

Requirement: .NET 10.0 or later. PortAudio can be installed system-wide for optimal audio quality; otherwise the bundled MiniAudio backend is used automatically.


Full Changelog: v2.7.1...v3.0.3

OwnAudioSharp v2.7.1

Choose a tag to compare

@ModernMube ModernMube released this 08 Apr 19:26

OwnAudioSharp v2.7.1

What's New

Device Disconnect / Reconnect Recovery

Audio devices that are unplugged during playback or recording are now automatically detected
and re-connected when they reappear, without user intervention:

  • IAudioEngine.Status — new EngineStatus enum (Idle, Running, DeviceDisconnected, Error)
  • IAudioEngine.DeviceReconnected event — fired when the original device reappears and
    playback/recording has resumed
  • NativeAudioEngine monitors device availability; polling speeds up to 500 ms the moment
    a disconnect is detected so reconnection is noticed almost immediately
  • AudioDeviceReconnectedEventArgs carries the device name and which stream (input/output) recovered
  • All platform engines (WasapiEngine, CoreAudioEngine, PulseAudioEngine, AAudioEngine) expose
    the new Status / DeviceReconnected members
engine.DeviceReconnected += (_, e) =>
    Console.WriteLine($"Device '{e.DeviceName}' reconnected – resuming {e.StreamType}");

FileSource.PreBuffer()

A new public method that pre-fills the internal decoder buffer without transitioning to
Playing state. Use it in latency-sensitive paths to warm the buffer before Play() is called,
so that Play() returns immediately instead of blocking while the buffer fills:

source.PreBuffer();   // fills buffer in the background, state stays Stopped/Ready
// … UI work …
source.Play();        // returns immediately, no startup gap

DynamicAmpEffect — Full Property API

All internal tuning parameters of DynamicAmpEffect are now exposed as validated public
properties, making runtime adjustment possible without reflection:

Property Default Description
TargetRmsLevelDb −14 dB Target loudness for RMS-based gain riding
AttackTime 10 ms Gain-increase attack time
ReleaseTime 100 ms Gain-decrease release time
NoiseGateThresholdDb −60 dB Gate below which the signal is silenced
MaxGain Maximum allowed gain factor
MaxGainReductionDb 20 dB Maximum allowed gain reduction
RmsWindowSeconds 0.3 s RMS measurement window length
MaxGainChangePerSecondDb 6 dB/s Maximum rate of gain change

VST3 Plugin Loading — Async Background Processing

VST3 plugin loading is now fully asynchronous so the UI thread is never blocked during
the (potentially long) native plugin initialization:

  • LoadMasterEffectFromPathAsync off-loads new VST3PluginHost(path) to a background thread
    via Task.Run
  • All UI updates use Dispatcher.UIThread.InvokeAsync, including status messages,
    property change notifications, and command-CanExecute refreshes

VST3 Transport Control Support

VST3 plugins that use IProcessContext (tempo, transport state, sample position) now receive
correct host transport information:

  • VST3EffectProcessor.SetTempo(double bpm) — forwards the current project BPM to the plugin's
    ProcessContext
  • VST3EffectProcessor.SetTransportPlaying(bool playing) — signals play/stop transitions
  • VST3EffectProcessor.ResetPosition() — resets the sample-position counter (e.g. on Stop)
  • Transport state is propagated to the plugin automatically when it is added to the mixer

VST3 Plugin Channel Count Auto-Detection

VST3EffectProcessor.Initialize() now reads OwnVst3Wrapper.ActualOutputChannels after native
initialization and uses it to allocate the planar output buffers. Plugins whose output bus
has a different channel count than the host config (e.g. mono-in / stereo-out effects) no
longer need special-casing.


Waveform Rendering — Full Floating-Point Precision

WaveDisplayControl rendering pipeline rewritten to use double coordinates throughout,
eliminating integer rounding drift that caused pixel-level jitter and edge clipping at
high zoom levels:

  • startSample and samplesPerPixel are now double, not int
  • Playback indicator computed directly as (position − scrollOffset) × zoom × width
    (no intermediate integer conversion)
  • Per-pixel sample range clamped with double arithmetic to prevent reading past the
    end of the waveform buffer

Bug Fixes

Audio Crackling on SoundTouch Transitions (FileSource)

Switching between SoundTouch processing (tempo/pitch active) and the direct bypass path
previously caused an audible click because Flush() appended a block of zero-padding
samples to the pipeline. The transition logic has been rewritten:

  • ON → OFF: internal SoundTouch pipeline is drained (no Flush(), no silence injection)
    — only the already-queued real audio comes out
  • OFF → ON: SoundTouch state is cleared so no stale data from a previous session bleeds in
  • _wasSoundTouchProcessing is updated before the write so the next decode cycle sees the
    correct state immediately

Thread-Safe CircularBuffer.Clear()

CircularBuffer.Clear() previously had a race condition with concurrent Write() calls:
zeroing _available while a write was in progress could cause the subsequent
Interlocked.Add to go negative, corrupting the buffer's bookkeeping:

  • A volatile bool _clearRequested flag replaces the direct clear
  • Write() and Read() consume the flag atomically at the start of each cycle under lock
  • Available returns 0 immediately when a clear is pending, making the state visible to
    callers without waiting for the next read/write cycle

VST3 maxBlockSize Mismatch (Silence on Similar Plugins)

AudioMixer._config.BufferSize was set to _engine.FramesPerBuffer (the hardware callback
size, e.g. 512 frames), while the mixer actually processes _bufferSizeInFrames frames per
cycle (e.g. 1024). VST3 plugins that strictly honour maxSamplesPerBlock received more samples than declared in setupProcessing() and silently output zeros.

  • AudioMixer._config.BufferSize is now set to _bufferSizeInFrames so effects are
    initialized with the correct maximum block size
  • VST3EffectProcessor.Process() re-invokes _vst3.Initialize() if frameCount ever
    exceeds the declared block size (safety net for dynamic buffer size changes)

VST3 Deadlock / Silence on macOS

Some VST3 plugins use Steinberg's MacPlatformTimer (backed by CFRunLoop) for internal
state management — including during audio processing. Without regular ProcessIdle() calls
on the macOS main thread, those timers never fire, causing the plugin to either output silence
or deadlock on the first process() call.

VstEditorController already ran an idle thread when the editor window was open. The fix
extends this to the plugin lifetime:

  • VST3PluginHost.ProcessIdle() — new public method wrapping OwnVst3Wrapper.ProcessIdle()
  • MainWindowViewModel starts a DispatcherTimer (20 ms / 50 Hz, UI thread) as soon as a
    plugin is loaded; the timer calls ProcessIdle() regardless of whether the editor is open
  • The timer is stopped when the plugin is removed or the view-model is disposed

VST3 Double Initialization Warning

AddMasterEffect() always called effect.Initialize(_config) on the effect, even if
VST3EffectProcessor.Initialize() had already been called from the loading path.

VST3EffectProcessor.Initialize() now skips the native _vst3.Initialize() call when the
plugin is already initialized with the same sample rate and buffer size.


AudioMixer Improvements

  • AudioMixer.Lifecycle: improved source lifecycle tracking and graceful shutdown ordering
  • AudioMixer.SourceManagement: RemoveSource now correctly handles sources that are
    mid-playback without triggering spurious PlaybackEnded events
  • AudioMixer.MixThread: mix-thread exception handling made more defensive; a single
    faulting source no longer stalls the mix cycle

Effects — Minor Fixes and Docs

  • CompressorEffect: corrected gain-computation edge case at ratio = ∞ (limiter mode)
  • FlangerEffect, LimiterEffect, PhaserEffect: XML documentation added; minor
    parameter validation improvements

Tests

  • DeviceDisconnectTests (575 lines): new integration-test suite covering device
    disconnect detection, reconnect recovery, status transitions, and the DeviceReconnected
    event on all engine paths

NuGet Packages

Package Target Version
OwnAudioSharp Windows / Linux / macOS (net9.0) 2.7.1
OwnAudioSharp.Mobile Android / iOS (net9.0-android, net9.0-ios) 2.7.1
OwnAudioSharp.Basic Windows / Linux / macOS (net9.0) 2.7.1
dotnet add package OwnAudioSharp --version 2.7.1
dotnet add package OwnAudioSharp.Mobile --version 2.7.1
dotnet add package OwnAudioSharp.Basic --version 2.7.1

Full Changelog: V2.6.8...v2.7.1