Skip to content

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 21 Aug 21:13
· 58 commits to main since this release

✨ Added

  • An Android tablet now finds hosts on the network by itself, like every other
    platform. It held a multicast socket that never received an answer, because
    Android's Wi-Fi driver discards multicast for an app that is not holding a
    WifiManager.MulticastLock — silently, with the search still saying it was
    looking. The lock is held while a search is running and given back when it
    stops, so it costs nothing once a display is attached.
  • An Android tablet now remembers its layout, its skin and the host it was last
    attached to. Nothing in an Android process names a directory it may write to,
    so the configuration directory is asked for over a platform channel and lives
    in the app's own files directory; every launch before this one started from
    the defaults.
  • Metering your Mac's own output no longer needs a loopback driver. On macOS
    14.2 and later, System Output is the first entry in the source menu, named
    after the output device it is metering. It is a Core Audio process tap, so
    there is nothing to install, nothing to reroute and no password prompt — the
    audio still reaches your speakers while it is being measured. macOS may ask
    for permission to record system audio the first time. Below 14.2 the entry is
    absent and BlackHole or Loopback is still the answer; Windows and Linux are
    unaffected, since WASAPI loopback and a PipeWire monitor source already appear
    in the list.

⚡ Changed

  • The wire protocol is at version 3, and a receiver now accepts any version it
    knows rather than only its own. A plugin built against 0.3.0 keeps working
    with a newer app, which under the old equality check it would not have: a
    plugin lives in the DAW's plugin folder and stays there across app upgrades,
    so the mismatch was the ordinary case, and what it looked like from the plugin
    was a port that accepts and hangs up forever — indistinguishable from the
    defect where the port was never bound at all. The rule is one-way on purpose:
    a peer newer than this build is still refused, because a later version may
    have moved a table and misreading a measurement table is how a meter draws a
    confident wrong number. A tablet still running 0.3.0 or earlier will refuse
    a newer desktop
    and say so, rather than drawing anything; update both ends.
    Version 3 adds a frame type and moves no byte of any existing table — held by
    a test that decodes the frozen version-2 golden and diffs it against the
    version-3 one, where exactly four bytes differ and all four are version
    fields.
  • A host search that is running but cannot receive says so instead of
    "Looking for hosts on this network…", which is the face a search that is about
    to succeed wears.

🐛 Fixed

  • The plugin's status panel no longer claims a playhead from a host that is not
    giving one. The line was drawn from whether a transport had ever been
    published, and the plugin publishes one for every audio block — the empty one
    that means "this host said nothing" included — so it read as a playhead the
    moment audio started flowing, on precisely the host it exists to warn about.
    It now follows what the host is reporting now, and says "no playhead from
    host" again if a host stops.

🚧 Internal

  • Groundwork for the Elapsed and Timecode LUFS modes, which are not yet
    offered by any module
    — this is the protocol and the engine underneath them,
    and the modules and their menu are the change after this one. docs/WIRE.md
    gains 0x0020 SET_LUFS_MODE, the first frame that travels from consumer to
    producer, permitted on the ingest port only because that one binds loopback
    where whatever connects is already running as this user; the display port
    binds every interface and stays read-only until somebody designs
    authentication for it. Three implementations moved together, as that file
    requires.
  • The engine can reset itself when the signal returns after a silence
    (oaa_engine_set_silence_reset, ABI 5), which is what the System mode is made
    of. It lives in engine/ rather than above it because silence is a property
    of audio and not of a host — one implementation serves a plugin and a sound
    card, where two would eventually disagree about when a track began. The gate
    runs before the block it judges, so a track whose loudest sample is in its
    first block keeps that peak rather than having it cleared by its own reset.
    Off by default, and off for file analysis, which must measure a file whole.
    The two transport-driven modes need no engine API at all: they are the
    producer declining to push, so engine/ still does not learn what a DAW is.
  • The plugin's answer to a host that supplies no transport is now held by a
    test. plugin/test/transport_capture_test.cpp hosts the AudioProcessor
    directly, which is the only way to reach either of the two branches behind it:
    no VST3 or Audio Unit host can express "no playhead" or "no position", so
    neither a DAW nor the fake DAW can ask for them. It runs in the gated plugin
    job's ctest, and both it and the transport box's own test were verified by
    breaking the code under them and watching them fail.
  • Five documents caught up with protocol version 3's two goldens. docs/WIRE.md
    still gave the SNAPSHOT payload size "at protocol version 2" in the one
    document whose header declares version 3; packages/oaa_wire/AGENTS.md named
    wire_v2.bin as the golden its codec test decodes, when the test reads both
    and wire_v3.bin is the one tracking the current serialiser; and two comments
    in ci.yml credited the C++ producing side with writing wire_v2.bin, which
    it no longer does. The one that could have cost something: the regeneration
    command in plugin/test/wire_fixture.cpp still wrote to wire_v2.bin — the
    frozen file whose whole purpose is to hold bytes produced before version 3
    promised to move no table. Following it would have destroyed the evidence and
    left every test green.
  • Two claims about that branch are corrected here rather than in the 0.3.0
    notes, which are released. It is not reached by the Standalone build —
    JUCE 8's AudioProcessorPlayer installs a counting playhead whenever the
    processor it is given has none — and it is unreachable through an Audio Unit
    as well, not only through VST3. The plugin's own handling was correct
    throughout; only the note about what exercised it was wrong. README.md no
    longer lists it under Known gaps, because it now has a test instead of a
    paragraph.