H073.HxWAV
1.0.0
Prefix Reserved
dotnet add package H073.HxWAV --version 1.0.0
NuGet\Install-Package H073.HxWAV -Version 1.0.0
<PackageReference Include="H073.HxWAV" Version="1.0.0" />
<PackageVersion Include="H073.HxWAV" Version="1.0.0" />
<PackageReference Include="H073.HxWAV" />
paket add H073.HxWAV --version 1.0.0
#r "nuget: H073.HxWAV, 1.0.0"
#:package H073.HxWAV@1.0.0
#addin nuget:?package=H073.HxWAV&version=1.0.0
#tool nuget:?package=H073.HxWAV&version=1.0.0
HxWAV
The code in this library is human-made — no AI was used to write it. This README, however, was generated with a locally running AI model.
Pure C# WAV / RIFF parser with no graphics or engine dependencies. Reads a .wav file (or stream) and decodes it to normalized 32-bit float samples, ready to hand to any audio backend. Handles the codecs and metadata chunks that show up in real-world files — PCM, IEEE Float, MS-ADPCM, IMA-ADPCM, loop points, cue markers, and INFO/BEXT tags.
.NET 8 / .NET 10 | zero dependencies
Features
- Codecs: PCM (8 / 16 / 24 / 32-bit), IEEE Float (32 / 64-bit), MS-ADPCM, IMA-ADPCM.
WAVE_FORMAT_EXTENSIBLEis unwrapped to its real sub-format automatically. - Normalized output: everything decodes to interleaved
float[]in the range[-1, 1], regardless of the source bit depth or codec. - Metadata:
LIST/INFOtags (title, artist, comment, genre, date, software, copyright) and Broadcast Wave (bext) description/originator. - Loops & markers: sampler loops (
smpl), cue points (cue) withadtllabels, and the MIDI unity note. - Robust: bounds-checked chunk walking, oversized/negative chunk handling, a 512 MB data-chunk safety cap, and pooled buffers (
ArrayPool) during decode. - Sync & async: read from a path or a
Stream, synchronously or withReadAsync.
Install
dotnet add package H073.HxWAV
Usage
Load a file
using HxWAV;
WavData wav = WavReader.Read("music.wav");
float[] samples = wav.Samples; // interleaved float, range [-1, 1]
int channels = wav.Channels;
int sampleRate = wav.SampleRate;
float seconds = wav.Duration;
int frames = wav.SampleFrameCount;
From a stream / async
using var stream = File.OpenRead("sfx.wav");
WavData wav = WavReader.Read(stream);
WavData wav = await WavReader.ReadAsync("music.wav", cancellationToken);
The WavData result
wav.Samples // float[] — interleaved samples, normalized to [-1, 1]
wav.Channels // channel count (e.g. 2 for stereo)
wav.SampleRate // Hz
wav.OriginalBitsPerSample // source bit depth before normalization
wav.OriginalCodec // WavCodec.Pcm / IeeeFloat / MsAdpcm / ImaAdpcm
wav.SampleFrameCount // Samples.Length / Channels
wav.Duration // seconds
wav.Metadata // WavMetadata? — INFO / bext tags
wav.Loops // WavLoopInfo[]? — sampler loop regions
wav.CuePoints // WavCuePoint[]? — markers (with labels if present)
wav.MidiUnityNote // root note for pitched samples (default 60)
De-interleaving to per-channel buffers
Samples is interleaved (L R L R …). To split a stereo clip:
float[] left = new float[wav.SampleFrameCount];
float[] right = new float[wav.SampleFrameCount];
for (int i = 0; i < wav.SampleFrameCount; i++)
{
left[i] = wav.Samples[i * 2];
right[i] = wav.Samples[i * 2 + 1];
}
Metadata, loops, and cue points
if (wav.Metadata is { } meta)
Console.WriteLine($"{meta.Artist} — {meta.Title}");
foreach (var loop in wav.Loops ?? [])
Console.WriteLine($"Loop {loop.Start}..{loop.End} (type {loop.Type}, play {loop.PlayCount})");
foreach (var cue in wav.CuePoints ?? [])
Console.WriteLine($"Cue #{cue.Id} @ frame {cue.Position}: {cue.Label}");
WavLoopInfo.Type: 0 = forward, 1 = alternating, 2 = backward. PlayCount of 0 means infinite. WavLoopInfo positions and WavCuePoint.Position are in sample frames.
Diagnostics
Parsing is silent by default. Attach a log sink to trace chunk walking and decode timings:
WavDiagnostics.Log = msg => Console.WriteLine(msg);
// WavDiagnostics.IsEnabled reflects whether a sink is attached
Error Handling
All failures throw a WavException (or a subclass), each carrying the offending FilePath:
| Exception | Thrown when |
|---|---|
WavParseException |
Malformed structure — bad RIFF/WAVE magic, missing fmt /data, truncated chunk |
WavFormatException |
Valid structure but unsupported/invalid format — carries the ChunkName and details |
WavBufferException |
Data chunk exceeds the 512 MB safety cap |
try
{
var wav = WavReader.Read(path);
}
catch (WavException ex)
{
Console.Error.WriteLine($"Failed to load {ex.FilePath}: {ex.Message}");
}
License
MIT
| Product | Versions 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 was computed. 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. |
-
net10.0
- No dependencies.
-
net8.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 |
|---|---|---|
| 1.0.0 | 100 | 7/1/2026 |