Releases: ModernMube/OwnAudioSharp
Release list
OwnAudioSharp v3.1.7
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
Positiondouble-tempo regression —Positionadvanced byframesRead × tempo / sampleRateinstead of wall-clock time. SoundTouch already applies the tempo conversion, so the extra factor double-counted it (regressing the v2.6.7 fix).Positionnow tracks wall-clock time in both standalone and synchronized read paths. OutputDeviceIdinitialization — 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.
VocalRemoveris 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
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
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.
FFmpegConfigclass 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
AudioDecoderFactoryselects 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+MIDIReceivedvia CoreMIDI - Linux: ALSA Sequencer (
snd_seq_t) — connectable viaaconnect
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:
FileSystemWatcheron/dev/sndvia 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 anIEffectProcessorchain directly on the decode path, before the sample reaches the mixerIEffectProcessorinterface updated with a unifiedProcess(Span<float>)contractVST3EffectProcessor: aligned to the updated interfaceSmartMasterEffect/SmartMasterAudioChain: accuracy and stability improvementsAutoGainEffect,LimiterEffect: added to the built-in effect setAudioMixer: 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
StartOffsetor non-defaultTempoare 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)replacesMarshal.SizeOf<T>()in all native call hot paths (WinMM MIDIHDR, ALSA Sequencer structs)ArrayPool<byte>.Sharedused for large SysEx payloads (>4 KB) on macOS; ≤4 KB paths usestackalloc- All new P/Invoke uses
[LibraryImport](source-generated, AOT-safe) - Platform selection is runtime via
RuntimeInformation.IsOSPlatform— no compile-time#ifrequired in application code
Tests
New MSTest project OwnAudio.MidiTest added:
MidiMessageconstruction and property correctness (24 tests)SysExReceivedHandlerdelegate behaviour (4 tests)AudioEngineMidiClockpulse timing and fractional accumulator (7 tests)MidiClockthread-based clock (11 tests)MidiPortFactoryenumeration 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
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 viaLockFreeRingBuffer.ReadMockAudioEngine: fills caller span in-place, removesnew float[]allocationAudioEngineWrapper: rents buffer fromAudioBufferPool, returns on error- All call sites updated to pre-allocate buffers
Bug Fixes
- Compiler warnings resolved: CS8604 null-reference warnings, MVVMTK0039
async voidRelayCommand, 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
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 0statement was missing after the deferred-clear block inWrite(), causing execution to fall through into the normal write path with a freshly-reset buffer. Samples written immediately after aClear()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
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:
ShouldFillBufferfill thresholds were inverted — the decoder stopped at 50% capacity whilePreBuffer/Playwaited for 75%, causing a 500 ms timeout on everyPlay()call when pitch or tempo was active. Thresholds are now correctly 75% (SoundTouch) / 50% (direct). - FileSource underrun volume:
ApplyVolumewas 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 beforeInterlocked.Add, potentially allowing CPU reordering of the read-pointer update on ARM64 (Apple Silicon, Linux arm64). Now consistent withWriteandRead. - MIDI SysEx on Linux: Replaces VLQ-based length parsing (SMF format) with proper raw MIDI byte-stream handling — scans for the
0xF7end-of-exclusive byte, clears running status after SysEx, and fixes running-status tracking for data-only bytes.
Dependencies
- Avalonia updated from
12.0.3→12.0.4 - OwnAudioVst updated from
1.6.0→1.6.3 - coverlet.collector updated from
10.0.0→10.0.1 - Microsoft.NET.Test.Sdk updated from
18.5.1→18.6.0 - FluentAssertions updated from
8.9.0→8.10.0
Documentation
- Channel Routing: Extended upmix/downmix guidance in the API Sources section.
- api-core: Documented
bufferMultiplierinInitializeexamples with a callout explaining when to increase it. - api-mixer: Added Heavy Load Setup section documenting
AudioMixer.CreatewithCircularBufferpre-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
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:
suggestedLatencyis now derived fromBufferSize / SampleRateinstead 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.21→1.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
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/GetOutputPortNamespreviously returned/dev/midi*OSS paths thatsnd_rawmidi_opencannot open. Now parses/proc/asound/rawmidifor ALSAhw:C,Dnames with direction filtering, with fallback to/dev/snd/midiCxDynode parsing.MidiPortFactoryresolves the friendly name to the correcthwpath before opening. - MaDecoder default channel count: Passing
0channels to the native decoder config now correctly defers channel selection to the native layer (previously hardcoded to2, 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
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 AudioEngineFactoryis now reflection-free — factory registration happens via[ModuleInitializer]inOwnaudio.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 codegenAudioEngineFactoryandAudioDecoderFactory— registration via[ModuleInitializer]delegate pattern, noAssembly.GetTypes()loopsGetManifestResourceNames()loops replaced with explicit AOT-safe resource namesJsonSerializerContextadded for SmartMaster preset serialization (IL2026/IL3050 clean)LibraryLoaderusesAppContext.BaseDirectoryinstead ofAssembly.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=trueNew 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
LibraryImportP/Invoke IMidiPort/IMidiInputPort/IMidiOutputPort— common port interfacesMidiFileReader/MidiFileWriter— pure C# Standard MIDI File parser with running-status compressionMidiClock— 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.3var 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
_positionclamp 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-queueSetParameter, this updates native controller state immediately without requiring aprocessAudiodrain 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
RouteInputChannelsfor physical input channels - Added
pInputnull-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_LENGTHcorrected to 255 (perminiaudio.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.4Requirement: .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
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— newEngineStatusenum (Idle,Running,DeviceDisconnected,Error)IAudioEngine.DeviceReconnectedevent — fired when the original device reappears and
playback/recording has resumedNativeAudioEnginemonitors device availability; polling speeds up to 500 ms the moment
a disconnect is detected so reconnection is noticed almost immediatelyAudioDeviceReconnectedEventArgscarries the device name and which stream (input/output) recovered- All platform engines (
WasapiEngine,CoreAudioEngine,PulseAudioEngine,AAudioEngine) expose
the newStatus/DeviceReconnectedmembers
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 gapDynamicAmpEffect — 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 |
4× | 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:
LoadMasterEffectFromPathAsyncoff-loadsnew VST3PluginHost(path)to a background thread
viaTask.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
ProcessContextVST3EffectProcessor.SetTransportPlaying(bool playing)— signals play/stop transitionsVST3EffectProcessor.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:
startSampleandsamplesPerPixelare nowdouble, notint- Playback indicator computed directly as
(position − scrollOffset) × zoom × width
(no intermediate integer conversion) - Per-pixel sample range clamped with
doublearithmetic 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
_wasSoundTouchProcessingis 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 _clearRequestedflag replaces the direct clear Write()andRead()consume the flag atomically at the start of each cycle under lockAvailablereturns0immediately 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.BufferSizeis now set to_bufferSizeInFramesso effects are
initialized with the correct maximum block sizeVST3EffectProcessor.Process()re-invokes_vst3.Initialize()ifframeCountever
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 wrappingOwnVst3Wrapper.ProcessIdle()MainWindowViewModelstarts aDispatcherTimer(20 ms / 50 Hz, UI thread) as soon as a
plugin is loaded; the timer callsProcessIdle()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 orderingAudioMixer.SourceManagement:RemoveSourcenow correctly handles sources that are
mid-playback without triggering spuriousPlaybackEndedeventsAudioMixer.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 theDeviceReconnected
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