ArtificialNecessity.Audio 0.1.7

Prefix Reserved
dotnet add package ArtificialNecessity.Audio --version 0.1.7
                    
NuGet\Install-Package ArtificialNecessity.Audio -Version 0.1.7
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ArtificialNecessity.Audio" Version="0.1.7" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ArtificialNecessity.Audio" Version="0.1.7" />
                    
Directory.Packages.props
<PackageReference Include="ArtificialNecessity.Audio" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ArtificialNecessity.Audio --version 0.1.7
                    
#r "nuget: ArtificialNecessity.Audio, 0.1.7"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ArtificialNecessity.Audio@0.1.7
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ArtificialNecessity.Audio&version=0.1.7
                    
Install as a Cake Addin
#tool nuget:?package=ArtificialNecessity.Audio&version=0.1.7
                    
Install as a Cake Tool

AN.Audio

https://github.com/ArtificialNecessity/AN_Audio

(C)opyright David Jeske 2026. Coded with Opus 4.6. Released under Apache 2.0 for all to share and enjoy.

Cross-platform audio playback for .NET via direct PInvoke to native OS APIs. A single managed DLL — no native binaries to bundle, no NuGet packages with precompiled C blobs, no runtime dependencies beyond the operating system itself.

Why

The .NET audio ecosystem is fragmented: NAudio is Windows-only, OpenAL requires runtime installs, SDL2 wrappers need bundled native libraries, and miniaudio bindings still ship a C binary per platform. The actual OS audio APIs are simple — 4–8 native calls each — they just aren't exposed cleanly from managed code.

AN.Audio calls them directly through PInvoke and manual COM vtable dispatch, producing a single AnyCPU MSIL assembly that works everywhere .NET runs.

Status

Platform Backend Status
Windows WASAPI (shared mode, event-driven) ✅ Working
macOS AudioQueue (AudioToolbox) ✅ Working
Linux ALSA (libasound.so.2) 🔲 Planned
Android AAudio 🔲 Future
iOS AudioQueue (AudioToolbox) 🔲 Future

API

using AN.Audio;

// Describe the format you want to work with
var format = new AudioFormat(SampleRate: 48000, Channels: 2, Format: SampleFormat.Float32);

// Create the platform-appropriate output (auto-detects OS)
using var output = AudioOutput.Create(format, bufferSizeMs: 20);

// Start playback — your callback runs on a dedicated audio thread
output.Start((Span<byte> buffer, int frameCount, AudioFormat fmt) =>
{
    // Write interleaved PCM samples into buffer.
    // Return the number of frames actually written.
    // Remainder is filled with silence.
    return frameCount;
});

// ... later
output.Stop();

The callback is the only extension point. It runs on a high-priority audio thread and must be fast — no allocations, no blocking locks, no I/O.

Key Types

Type Purpose
AudioFormat Sample rate, channel count, sample format (Int16 or Float32)
AudioCallback delegate int(Span<byte>, int, AudioFormat) — fills the buffer
IAudioOutput Start/Stop/Dispose + Format and LatencyMs properties
AudioOutput Static factory — creates the right backend for the current OS

Format Negotiation

On Windows, WASAPI shared mode dictates the endpoint format (typically 48kHz/stereo/float32). The IAudioOutput.Format property reports what the backend is actually using — your callback must produce samples in that format. If your source data differs, convert in the callback.

Building

dotnet build AN.Audio.slnx

After clone, generate the version props file first:

./cmd/gen-version-file.ps1
dotnet build

Publishing to Local NuGet Feed

$env:LOCAL_NUGET_REPO = "C:\path\to\local\feed"
./cmd/publish-local.ps1

This increments the version, builds, packs ArtificialNecessity.Audio, and deploys the .nupkg to your local feed.

Project Structure

AN.Audio/
├── src/AN.Audio/                    # The library
│   ├── IAudioOutput.cs              # Interface + AudioCallback delegate
│   ├── AudioFormat.cs               # Format descriptor + SampleFormat enum
│   ├── AudioOutput.cs               # Platform-detecting factory
│   └── Platforms/
│       ├── Windows/
│       │   ├── WasapiAudioOutput.cs  # WASAPI event-driven backend
│       │   └── WasapiInterop.cs     # COM vtable structs + PInvoke
│       └── MacOS/
│           ├── CoreAudioOutput.cs    # AudioQueue callback-driven backend
│           └── AudioToolboxInterop.cs # AudioQueue PInvoke
├── tests/SimpleAudioTest/           # Standalone console test (plays a WAV file)
├── AN.Audio.Build.props             # Shared build infrastructure
├── version.jsonc                    # Version source of truth
└── cmd/
    ├── gen-version-file.ps1         # Generate version props from version.jsonc + git
    └── publish-local.ps1            # Build + pack + deploy in one step

Design Principles

  • Zero native dependencies — the audio APIs are part of the OS. Nothing to bundle or install.
  • Event-driven — the OS signals when it needs samples. No polling, no spin-waits.
  • Zero-allocation hot path — the audio callback receives a Span<byte> over the hardware buffer. No copies, no GC pressure.
  • One backend per platform — each is ~200–400 lines of interop code wrapping 4–8 native calls.
  • Playback only — capture/recording is a separate concern for the future.
Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.7 94 5/16/2026
0.1.6 86 5/16/2026
0.1.5 80 5/16/2026
0.1.4 89 5/16/2026
0.1.3 97 5/16/2026