EggEncoder 4.40.0
See the version list below for details.
dotnet add package EggEncoder --version 4.40.0
NuGet\Install-Package EggEncoder -Version 4.40.0
<PackageReference Include="EggEncoder" Version="4.40.0" />
<PackageVersion Include="EggEncoder" Version="4.40.0" />
<PackageReference Include="EggEncoder" />
paket add EggEncoder --version 4.40.0
#r "nuget: EggEncoder, 4.40.0"
#:package EggEncoder@4.40.0
#addin nuget:?package=EggEncoder&version=4.40.0
#tool nuget:?package=EggEncoder&version=4.40.0
π₯ EggEncoder
Audio encoding/decoding toolkit for .NET β 12 formats (AAC, AIFF incl. AIFC, ALAC, AU, FLAC, MP3, Opus, TTA, Vorbis, WAV incl. IMA/MS/Yamaha ADPCM and G.711, WavPack, WMA) plus MOV/MP4 probing, entirely pure C#, built-in waveform generation, and an opt-in PCM transform pipeline (resampling, gain/peak normalization, dynamics compression, noise gating, peak limiting, echo/delay, pan/balance, channel remix, fades, parametric EQ, FIR filtering, mixing), all behind one
IMediaEncoderinterface.
Sponsored by eggspot.app
Overview
EggEncoder gives you a single IMediaEncoder abstraction β Probe, ConvertFile, CutFile β implemented entirely in-process by NativeEncoder: pure .NET codec implementations for every supported format (AAC, WAV, AIFF, AU, ALAC, FLAC, MP3, TTA, WMA, Opus, Vorbis, WavPack). No external process, no ffmpeg install, no subprocess overhead.
Why EggEncoder?
- π Entirely pure managed, fully in-process β no codec shells out to native P/Invoke any more (MP3 encode is now a clean-room managed implementation, same as every other format here); no subprocess/shell-out overhead anywhere
- βοΈ Native AOT compatible β no reflection, no dynamic code; publish with
PublishAot=trueand it just works - πΌ Broad format coverage β AAC, AIFF (incl. AIFC), ALAC, AU, FLAC, MP3, Opus, TTA, Vorbis, WAV, WavPack, WMA decode/encode; MOV/MP4 metadata probing + mono AAC-LC audio decode
- π Built-in waveform generation β normalized peak windows for any decoded stream
- π·οΈ WAV metadata tags β
Probesurfaces a WAV file's'LIST'/'INFO'chunk (title, artist, etc.) viaProbeResult.Tags - βοΈ Sample-accurate cutting β trim audio files without a full decodeβencode round trip
- ποΈ PCM transform pipeline β resampling, gain/peak normalization, channel remix, bit-depth/float conversion, fades, parametric EQ (biquad + Butterworth) and general FIR filtering, mixing, and concatenation β opt-in, composable, and layered onto
Convert/Cutwithout touching the original API - πͺΆ Dependency-light β only
Microsoft.Extensions.*.AbstractionsandNLayer - π MIT licensed β see THIRD-PARTY-NOTICES.md for the bundled native codec license (BSD-style libFLAC)
Installation
dotnet add package EggEncoder
A native codec binary (libFLAC.dll) ships inside the package for win-x64 and is copied to your output directory automatically.
Quick Start
using EggEncoder;
// Dependency injection (recommended)
builder.Services.AddEggEncoder();
public class MediaService(IMediaEncoder mediaEncoder)
{
public async Task<ProbeResult> Inspect(string filePath) =>
await mediaEncoder.Probe(filePath);
public Task Transcode(string sourcePath, string destPath) =>
mediaEncoder.ConvertFile(sourcePath, destPath);
public Task Trim(string sourcePath, string destPath, int startSeconds, int endSeconds) =>
mediaEncoder.CutFile(sourcePath, destPath, startSeconds, endSeconds);
}
Without DI
using EggEncoder;
using Microsoft.Extensions.Logging.Abstractions;
IMediaEncoder encoder = new NativeEncoder(NullLogger<NativeEncoder>.Instance);
var probeResult = await encoder.Probe("track.flac");
PCM Transform Pipeline
AddEggEncoder() also registers IPcmTransformEncoder (same NativeEncoder instance as IMediaEncoder) β an opt-in PcmTransformPipeline of composable IPcmTransforms that runs between decode and the destination write:
using EggEncoder.Codecs;
using EggEncoder.Pcm;
var pipeline = new PcmTransformPipeline(
new ResamplingTransform(sourceRate: 44100, targetRate: 48000, channels: 2),
new VolumeTransform(gain: 1.5));
AudioCutter.Convert(sourcePath, destPath, pipeline);
// or via DI: await pcmTransformEncoder.ConvertFile(sourcePath, destPath, pipeline);
// (pcmTransformEncoder: IPcmTransformEncoder, injected the same way as IMediaEncoder above)
// Float WAV destination (source stays a normal 32-bit int/float WAV; Float32 only changes the
// on-disk encoding of the destination -- see "Important limits" below):
AudioCutter.Convert(sourcePath, floatDestPath, WavSampleFormat.Float32);
Covers resampling (ResamplingTransform), gain / peak normalization (VolumeTransform / PeakNormalizationTransform), dynamics compression (CompressorTransform, threshold/ratio/attack/release/makeup gain), noise gating (NoiseGateTransform, the mirror-image downward expander below threshold), peak limiting (LimiterTransform, infinite-ratio compression plus a final per-sample hard clip, guaranteeing the output never exceeds the ceiling), echo / delay (EchoTransform, a feedback delay line with a decaying repeat tail drained via Flush), stereo pan/balance (PanTransform, linear or equal-power), channel remix (ChannelRemixTransform, monoβstereo and general NβM), bit-depth and float conversion (BitDepthFormatTransform for 8/16/24/32-bit, FloatSampleConverter for intβIEEE-float), fades on a cut (FadeTransform via CutOptions), mixing / concatenation (AudioCutter.Mix, AudioCutter.Concatenate), parametric EQ filters (BiquadTransform β RBJ Audio EQ Cookbook low/high pass, band pass, notch, all pass, peaking EQ, low/high shelf β and ButterworthTransform for steeper cascaded low/high pass), and general FIR convolution (FirFilterTransform, arbitrary caller-supplied taps). Full walkthrough and type reference: Advanced Features / API Reference.
Important limits:
- A
PcmTransformPipelineinstance carries state across blocks (resampler history, fade position, measured peak gain, biquad/Butterworth/FIR filter history) β build a fresh one perConvert/Cut/Mixcall, don't reuse across calls. - A pipeline containing
ResamplingTransform(or any stateful transform implementingIPcmTransform.Flush) needspipeline.Flush(...)called once after the last block, to drain output the transform was still holding back βAudioCutter.Convert(pipeline)/Cut(options)already do this for you; only a driver written againstPcmTransformPipelinedirectly needs to call it itself. - True whole-file peak normalization needs
AudioCutter.MeasurePeakAmplitudefollowed byPeakNormalizationTransform.MeasurePeakbefore the pipeline runs β otherwise it silently normalizes against only the first decode block. Mix/Concatenaterequire every source to share the same channels/sample rate/bit depth.Mixdecodes all sources fully into memory (clip-length material, not multi-hour streams).ResamplingTransformis a Kaiser-windowed-sinc polyphase filter (anti-aliasing on downsample, band-limited reconstruction on upsample) β callFlush()(see above) to get its last few frames, which it can't produce until it either sees more input or is told there isn't any.
Supported Formats
| Format | Probe | Decode | Encode |
|---|---|---|---|
| WAV | β | β βΆ ΒΉΒΉ | β βΆ β· ΒΉΒΉ |
| AIFF | β | β βΉ | β βΉ |
| AU (.au) | β | β | β ΒΉβ° |
| ALAC (.caf) | β | β | β Β² |
| TTA | β | β | β Β² |
| WavPack (.wv) | β | β | β β΅ |
| Opus (.opus) | β | β | β Β³ |
| Vorbis (.ogg) | β | β | β β΄ |
| FLAC | β | β | β |
| MP3 | β | β | β |
| AAC | β | β | β |
| WMA | β | β | β |
| MOV/MP4 | β | β ΒΉ | β |
ΒΉ MOV/MP4 decode is audio-only, mono AAC-LC tracks β video frames are never decoded. Files without a matching audio track still probe fine (metadata only).
Β² ALAC supports 16-bit and 24-bit PCM for decode and encode (20-bit is out of scope β see AlacDecoder's doc comment); TTA is 16-bit PCM only (see TtaDecoder's doc comment). Mono and stereo are both supported by both.
Β³ Opus is lossy and fixed at 48kHz (Opus's native/highest internal rate) regardless of the source's own rate β resample first via ResamplingTransform if it isn't already 48kHz. Mono and stereo, 16-bit PCM, channel mapping family 0 only.
β΄ Vorbis is lossy, mono/stereo, 16-bit PCM β unlike Opus, any sample rate is supported (no fixed-rate resampling requirement).
β΅ WavPack supports 16-bit and 24-bit lossless integer PCM (its own lossy/hybrid and floating-point modes are out of scope). Mono and stereo only. Both WavPack decode and encode are pure managed implementations (clean-room from the WavPack 4/5 format spec plus, for the codec algorithm that spec doesn't itself document, an owner-approved arm's-length study of FFmpeg's own independently-written decoder β see THIRD-PARTY-NOTICES.md); no native binary is involved for this codec any more. The encoder is a deliberately simple MVP (a single fixed decorrelation term, independent-channel stereo, not yet compression-competitive) whose output round-trips exactly through this project's own decoder, but has not yet achieved full compatibility with the real reference wvunpack CLI for arbitrary content. Also unlike every other codec here, WavPack cannot represent an empty/zero-sample stream at all (confirmed from its own reference CLI, which refuses to encode one) β encoding one throws NotSupportedException rather than producing a file.
βΆ WavReader also decodes IMA ADPCM (WAVE_FORMAT_IMA_ADPCM, format tag 17) and MS ADPCM (WAVE_FORMAT_ADPCM, format tag 2, see footnote 8) β still a .wav file, just a different fmt chunk codec, so it's read automatically by Probe/Convert/Cut/pipeline sources with no extra API. Mono and stereo only; reports as 16-bit PCM once decoded (the coded width is 4 bits for both). WavWriter also encodes both (block-structured, buffered internally rather than one sample at a time β see WavSampleFormat.ImaAdpcm/ImaAdpcmEncoder and WavSampleFormat.MsAdpcm/MsAdpcmEncoder), selectable the same way Float32/MuLaw/ALaw are.
β· WavReader/WavWriter also decode/encode G.711 companded PCM (WAVE_FORMAT_ALAW/WAVE_FORMAT_MULAW, format tags 6/7) β again still a .wav file, read/written automatically with no extra API beyond WavSampleFormat.ALaw/MuLaw as a Convert/Cut/Mix/Concatenate destination, the same way Float32 works. Any channel count (G.711 has no structural reason to limit it, unlike every other codec here); reports/requires 16-bit PCM at the boundary (the coded width is 8 bits). Unlike IMA ADPCM's own block-structured encode, G.711 has no block structure or adaptive state at all, so its own encode is a simple one-sample-at-a-time companding formula.
βΈ MS ADPCM (WAVE_FORMAT_ADPCM, format tag 2), mono and stereo only β a genuinely different algorithm from IMA ADPCM (linear prediction from a per-file coefficient table carried in the fmt chunk itself, rather than IMA ADPCM's universal fixed step table), so it's its own decoder and encoder, not a variant of ImaAdpcmDecoder/ImaAdpcmEncoder. MsAdpcmEncoder always selects the standard table's simplest coefficient pair (predictor index 0) for every block β confirmed from FFmpeg's own real encoder that this, not a per-block search over the other 6 standard pairs, is what real-world encoders actually ship β and always writes that full 7-pair standard table into the file's own fmt chunk extension regardless.
βΉ AiffReader/AiffWriter also handle AIFC (FORM/AIFC), still under the .aiff/.aif/.aifc extensions β no separate dispatch, AiffReader just understands the AIFC form type's extra compressionType field in its COMM chunk. Covers NONE/twos (big-endian PCM, the same as plain AIFF), sowt (little-endian PCM), fl32/fl64 (big-endian IEEE float, decoded at this codebase's usual int32-native-range scale β both report 32-bit PCM resolution), and alaw/ulaw (G.711, reusing the same G711Codec the WAV side uses, not a second implementation) β all read AND write, selectable on write via AiffSampleFormat (see AudioCutter.Convert(..., AiffSampleFormat)/CutOptions.DestinationAiffFormat). ima4 (QuickTime IMA4 ADPCM, decode only) is also covered β a materially different bitstream from WAV's own IMA ADPCM (no verbatim first sample per block, and for stereo each channel's own 34-byte sub-block is written whole rather than nibble-interleaved), though the underlying per-nibble math is identical and reused directly from Wav.ImaAdpcmDecoder β see Ima4Decoder.
ΒΉβ° AU (Sun/NeXT, magic .snd) has no chunk structure at all β one fixed 24-byte header, optionally followed by an annotation string, then raw big-endian samples with no byte-alignment padding. Covers 8/16/24/32-bit signed integer PCM, 32/64-bit IEEE float (both reporting 32-bit PCM resolution, the same reasoning as AIFC's own fl64), and mu-law/A-law G.711 (again reusing G711Codec) β all read AND write, selectable on write via AuSampleFormat (see AudioCutter.Convert(..., AuSampleFormat)/CutOptions.DestinationAuFormat). Every other defined AU encoding (G.721/G.722/G.723 ADPCM, fragmented samples) is real but obscure and out of scope, the same way AIFC's MAC3/MAC6 (MACE) are.
ΒΉΒΉ Yamaha ADPCM (WAVE_FORMAT_YAMAHA_ADPCM, format tag 32), mono and stereo only, full decode AND encode (YamahaAdpcmDecoder/YamahaAdpcmEncoder) β still a .wav file, read automatically by Probe/Convert/Cut/pipeline sources with no extra API, selectable on write via WavSampleFormat.YamahaAdpcm. Unlike IMA/MS ADPCM, it has no block structure at all β no per-block header, no wSamplesPerBlock fmt chunk extension β each channel's predictor/step state just carries continuously across the whole stream. Like MS ADPCM's own encoder (and unlike IMA ADPCM's own search), its nibble is computed via a direct closed-form formula, confirmed structurally identical to FFmpeg's own real adpcm_yamaha_compress_sample.
IMediaEncoder.CutFile decodes any supported source (WAV, AIFF, AU, ALAC, TTA, WavPack, Opus, Vorbis, FLAC, MP3, AAC, WMA, and MOV/MP4 files with a mono AAC-LC audio track) and can cut into any supported destination format, including converting as it trims β sample-accurate, no re-encode of the untouched region.
WAV supports 8-bit unsigned, 16/24/32-bit signed integer, and 32-bit IEEE float PCM (read and write), plus IMA ADPCM decode+encode, MS ADPCM decode+encode, Yamaha ADPCM decode+encode, and G.711 mu-law/A-law decode+encode (see footnotes 6/7/8/11 above). AIFF (.aiff/.aif/.aifc) supports 8/16/24/32-bit signed integer PCM, read and write (plain FORM/AIFF), plus AIFC (FORM/AIFC) read and write for NONE/twos/sowt integer PCM, fl32/fl64 float, and alaw/ulaw G.711, plus ima4 (QuickTime IMA4 ADPCM) decode (see footnote 9). AU (.au) supports 8/16/24/32-bit signed integer PCM, 32/64-bit float, and mu-law/A-law G.711, all read and write (see footnote 10). ALAC (.caf, Apple Lossless in a CAF container) supports mono and stereo, 16-bit or 24-bit integer PCM, read and write. TTA (.tta, True Audio) supports mono and stereo, 16-bit integer PCM, read and write. WavPack (.wv) supports mono and stereo, 16-bit or 24-bit lossless integer PCM, read and write. Opus (.opus, in a from-scratch OggOpus container) supports mono and stereo, 16-bit integer PCM at a fixed 48kHz, read and write. Vorbis (.ogg) supports mono and stereo, 16-bit integer PCM at any sample rate, read and write. A float WAV source always decodes transparently into int PCM, the same as any other bit depth. For a float, mu-law, A-law, IMA ADPCM, MS ADPCM, or Yamaha ADPCM WAV destination, pass WavSampleFormat.Float32/MuLaw/ALaw/ImaAdpcm/MsAdpcm/YamahaAdpcm to AudioCutter.Convert/Cut (via CutOptions.DestinationWavFormat)/Mix/Concatenate β the default (WavSampleFormat.Integer) is unchanged; Float32 requires the destination's bit depth to already be 32, MuLaw/ALaw/ImaAdpcm/MsAdpcm/YamahaAdpcm require 16 (widen/narrow with BitDepthFormatTransform first if needed), and ImaAdpcm/MsAdpcm/YamahaAdpcm additionally require mono or stereo. AudioCutter.ReadWavAsFloat/WriteWavFromFloat/FloatSampleConverter remain available for working with float[] directly instead of driving int PCM through a pipeline.
License
MIT β see LICENSE. EggEncoder bundles a pre-built libFLAC.dll (BSD-style) as a
separate, dynamically-loaded native binary; see
THIRD-PARTY-NOTICES.md for details.
| 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 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. |
-
net10.0
- Concentus (>= 2.2.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- NLayer (>= 2.0.1)
- NVorbis (>= 1.0.0-rc.2)
- OggVorbisEncoder (>= 1.2.2)
-
net8.0
- Concentus (>= 2.2.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- NLayer (>= 2.0.1)
- NVorbis (>= 1.0.0-rc.2)
- OggVorbisEncoder (>= 1.2.2)
-
net9.0
- Concentus (>= 2.2.2)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.0)
- NLayer (>= 2.0.1)
- NVorbis (>= 1.0.0-rc.2)
- OggVorbisEncoder (>= 1.2.2)
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 |
|---|---|---|
| 4.42.0 | 0 | 10/11/2026 |
| 4.41.1 | 0 | 10/11/2026 |
| 4.41.0 | 0 | 10/11/2026 |
| 4.40.0 | 0 | 10/11/2026 |
| 4.39.0 | 39 | 10/10/2026 |
| 4.38.1 | 39 | 10/10/2026 |
| 4.38.0 | 43 | 10/10/2026 |
| 4.37.0 | 42 | 10/10/2026 |
| 4.36.0 | 44 | 10/10/2026 |
| 4.35.0 | 46 | 10/10/2026 |
| 4.34.0 | 41 | 10/10/2026 |
| 4.33.0 | 41 | 10/10/2026 |
| 4.32.1 | 45 | 10/10/2026 |
| 4.32.0 | 48 | 10/10/2026 |
| 4.31.0 | 40 | 10/9/2026 |
| 4.30.0 | 42 | 10/9/2026 |
| 4.29.3 | 44 | 10/9/2026 |
| 4.29.2 | 47 | 10/8/2026 |
| 4.29.1 | 43 | 10/8/2026 |
| 4.29.0 | 43 | 10/8/2026 |