Skip to content

OwnAudioSharp v4.0.9

Choose a tag to compare

@ModernMube ModernMube released this 10 Oct 08:56
· 30 commits to main since this release

Three Own* effects, a matchering built on them, and network sync that syncs

4.0.9 adds three effects written for the Rust engine from the start: OwnCompressorEffect,
OwnDelayEffect and OwnDynamicAmpEffect, a loudness-based level rider. Matchering now builds its
whole dynamics stage on the compressor and the rider, and its loudness is measured in LUFS instead
of RMS dBFS.

Chord detection now follows the beat of the song and names inversions. Network sync had
not been working at all, so it is rewritten: clients follow the server on their own clock. On mobile,
OwnAudioSharp.Mobile drops Avalonia and carries MIDI.

The full detail is in CHANGELOG.md,
under the 4.0.9-preview sections.

OwnCompressor, OwnDelay, OwnDynamicAmp

var vocal = new SourceWithEffects(vocalSource);
vocal.AddEffect(new OwnCompressorEffect(OwnCompressorPreset.Vocal));

var echo = new OwnDelayEffect(OwnDelayPreset.TapeEcho);
echo.SyncToTempo(bpm: 92, OwnDelayNoteValue.Quarter, OwnDelayNoteValue.Eighth);
vocal.AddEffect(echo);

var rider = new OwnDynamicAmpEffect(OwnDynamicAmpPreset.Broadcast);
mixer.AddMasterEffect(rider);
// rider.ProgramLoudness, rider.CurrentGainDb, rider.LimiterGainReductionDb read it back
  • OwnCompressorEffect is a log-domain compressor with:

    • a soft knee up to 24 dB and look-ahead up to 10 ms
    • programme-dependent auto release
    • peak or RMS detection, feed-forward or feedback topology
    • stereo link and mid/side processing
    • a sidechain high-pass and a range that caps the deepest reduction
    • auto makeup, and a parallel mix whose dry path is delayed by the look-ahead so it never comb-filters

    Nine presets, from Vocal and Bus to Mastering and Parallel.

  • OwnDelayEffect is a tape-style stereo delay:

    • in-loop ADAA saturation, diffusion and low/high cut, so each repeat darkens and smears
    • glide or crossfade when the time changes
    • wow, ping-pong, ducking, width and freeze
    • tempo sync to straight, dotted or triplet note values

    Nine presets.

  • OwnDynamicAmpEffect is the grown-up twin of DynamicAmpEffect:

    • it measures BS.1770 loudness and follows a gated programme estimate over a 0.4–60 s window
    • it leaves material inside its tolerance alone
    • passages under the gate and silence below the freeze threshold never move the gain, so a
      pianissimo stays one and room noise is not pumped up
    • a 4× true-peak look-ahead limiter holds the ceiling in dBTP

    Seven presets, from Speech and Broadcast to Mastering.

All three run natively, like every other effect. Delay compensation now tracks look-ahead changes:
moving the look-ahead of an effect already on the mixer re-aligns the tracks. A bypassed
OwnCompressor or OwnDynamicAmp keeps passing the delayed dry signal, so its track stays aligned.

Matchering on the new dynamics

  • The offline render is EQ → OwnCompressor → OwnDynamicAmp. The separate compressor, dynamic
    amp and limiter are gone; the rider's true-peak limiter is the last stage.
  • Two passes. The first pass measures what the EQ and the compressor leave, so the rider starts
    on exactly the gain the target needs instead of slewing there.
  • Latency compensation covers every look-ahead in the chain.
  • The compressor takes the source's peak-to-loudness ratio to the target's, and its range stops
    it there, so it never squashes further than the match asks.
  • AudioAnalyzer.MeasureLoudness and AudioSpectrum.LoudnessStats measure a whole track the way
    the rider hears it: gated integrated LUFS, EBU Tech 3342 loudness range, 4× true peak, noise floor
    and side/mid balance.
  • The settings a match settled on are kept. MatcheringProfile.Compressor and .Leveler hold
    them, and ApplyTo sets them on a live effect in one call.
  • Playback presets have their own setups. PlaybackPreset.Compressor and .Leveler give each
    playback system its own compressor and rider.

Chord detection

  • Follows the beat. With a tempo, SongChordAnalyzer tracks the beats from the note onsets,
    finds the phase and follows a tempo that drifts, so chord changes land on the beats.
  • Names inversions. When a chord tone other than the root holds the bass, the name carries it
    after a slash: C/E, Am/C.
  • A cleaner chromagram. Notes above E5 count less, so a melody line doesn't pass for a chord
    tone. The chroma is log-compressed, so a root doubled in three octaves no longer drowns out the
    third.
  • Minor keys include the raised leading tone. In A minor, E and E7 count as in key.
  • No holes, no overlaps. A segment shorter than the minimum gives its time to its neighbours,
    and the reported TimedChord spans tile the song.
  • Pruning keeps the bass. When notes are pruned, the bass note is always kept.
  • Custom templates take effect at once. A template added with AddChordTemplate works
    immediately and survives a key change.

Network sync, rebuilt

Before this release, no command reached the clients:

  • every command was 73 bytes on the wire, but the reader waited for 256
  • the server never read its socket, so pings went unanswered
  • each client overwrote its clock with the server's raw timestamp 100 times a second

Now the client runs on its own clock:

  • an NTP-style offset is taken from the fastest round trips
  • the server streams the song position it actually hears
  • a proportional tempo trim of at most ±0.5% (MasterClock.TempoTrim) pulls the client in
  • a seek happens only past 80 ms of drift
  • transport follows the server: the client starts where the server is, stops where it stands and
    jumps when it jumps

The server announces itself on every network card, so a client given no server address finds it.
BroadcastCommand works, and commands reach the app through
OwnaudioNet.NetworkSyncCommandReceived. The sync threads survive an exception. A client also goes
in when the server starts inside its offset silence.

Mobile

  • OwnAudioSharp.Mobile no longer depends on Avalonia, so it works under MAUI, Avalonia, Uno or
    native Android/iOS. It ships no visual controls any more. For a waveform, read
    FileSource.GetPeaks and draw it yourself.
  • The Mobile package carries MIDI. On iOS the MIDI exports live in the same libownaudio_ffi.a
    as the audio engine: two static Rust archives side by side broke the app's link with duplicate
    symbols. On iOS, MIDI imports from __Internal, so -dead_strip no longer removes its exports.

Fixes

  • MIDI system messages go out at their real length. Clock, Start, Continue and Stop used to be
    padded to three bytes (F8 00 00), and receivers could read the zeros as running status. An
    incoming clock is now TimingClock instead of SysEx, and MidiMessage.IsSystem is new.
  • SmartMaster's room measurement plays through the mixer it sits on. In rust-native mode its test
    noise never reached the speakers. Leaving the mixer cancels a running measurement before the
    microphone goes away.
  • Disposing a mixer whose output device has disappeared no longer throws and no longer leaves
    the master effects behind.
  • The waveform control caches its geometry, so a moving playhead redraws one line instead of the
    whole wave. It decodes files off the UI thread and no longer cuts off the tail of long files.
  • Windows natives always ship with ASIO. The build now fails instead of silently falling back
    to WASAPI-only binaries.

Notes

  • Breaking, source level: chord names can contain a slash. TimedChord.ChordName and
    ChordAnalysis.ChordName can now carry one for an inversion, so code that looks a name up should
    split at / first. Ambiguous names in Optimized mode are now joined with " | " instead of "/".
  • Breaking, binary level: SongChordAnalyzer takes the tempo as float. Source passing an
    int compiles as before, but code built against an older version has to be recompiled.
  • Breaking, Mobile only: WaveDisplayControl is gone from OwnAudioSharp.Mobile. The desktop
    package keeps it.
  • Matchering loudness is LUFS. MatcheringProfile.TargetLoudness and SourceLoudness are now
    integrated LUFS, not RMS dBFS. Apart from these, the public API diff is additive, and
    ABI_VERSION stays 1.
  • Deprecated: SyncTolerance, SoftSyncTolerance, SoftSyncMaxTempoAdjustment and
    SyncDiagnostics, since the network sync now trims the tempo of the whole mixer. NetworkSyncStatus
    has the live numbers.
  • Microsoft.SourceLink.GitHub is now 10.0.303, for CVE-2026-62900. It is a build-time dependency
    and does not ship in the packages.
  • The MT3 package ships an osx-arm64 native but no osx-x64, so the backend does not load on Intel Macs.
  • The examples are rewritten for the 4.x API.
  • Documentation: modernmube.github.io/OwnAudioSharp

Full Changelog: V4.0.8...V4.0.9

Packages (NuGet)

Package Version
OwnAudioSharp 4.0.9
OwnAudioSharp.Basic 4.0.9
OwnAudioSharp.Mobile 4.0.9
OwnAudioSharp.Midi 4.0.9
OwnAudioSharp.Mt3 4.0.9