Skip to content

WASAPI Driver for ASIO 0.9.12

Pre-release
Pre-release

Choose a tag to compare

@github-actions github-actions released this 25 Oct 19:41
· 4 commits to main since this release

0.9.12 (changes from 0.9.11) - "Capture"; event-driven Exclusive capture

The second recording test (TEST-GUIDE.txt block AB on 0.9.11, Steinberg
UR22mkII with the Yamaha Steinberg USB Driver, Windows 11 x64, Cubase 15,
44.1 kHz) showed with the new "Capture:" counters WHY Exclusive mode at a
256 buffer still dropped and that a 512 buffer in Shared mode also lost
input. Both fixes are in this version; the output path is unchanged.
Summary of all changes:

  • KI-13 FIXED (to be confirmed by block AB on real hardware) - Exclusive
    capture is now EVENT-DRIVEN. 0.9.11 and earlier opened an Exclusive
    capture stream in polled mode (periodicity = the ASIO buffer size, a
    buffer of four periods) and drained it from the output wake-up with
    GetNextPacketSize. The Yamaha driver answered that call with 512-frame
    packets at EVERY 256-frame wake-up ("max packet 512 ... 1024", "empty 17
    of 8368 pulls"): twice the audio that existed. The FIFO grew by 256
    frames per wake-up and the overfill limit discarded real audio about
    once per 17 wake-ups (504 drops in 50 s, unusable recording). The limit
    change of 0.9.11 could only move the drop point. Now the capture stream
    is opened with AUDCLNT_STREAMFLAGS_EVENTCALLBACK, a periodicity equal to
    the device's DEFAULT period (what its driver processes natively; its
    minimum period if the default is below it) and a buffer of one period;
    the device driver signals an event of the stream's own once per period
    with exactly one packet, the audio thread waits on {stop, output event,
    capture events} and drains that source only when its event fires, never
    from the output wake-up. Nothing is polled, so no interpretation of
    GetNextPacketSize is needed. Independent review (R1): the periodicity
    is the smallest multiple of the device's default period that holds one
    ASIO buffer (the event-driven stream double-buffers one period, and a
    host callback must never outlast that window), the capture events come
    before the output event in the wait (a pending packet is drained before
    the long output service) and a packet already signalled is also drained
    between host callbacks. Input latency in Exclusive mode with buffers
    larger than the device's default period grows to that multiple (512 at
    44.1 kHz with a 441-frame default: period 882, about 20 ms). The FIFO
    target is one capture period + one output period + one capture period
    of margin (see KI-11). The log line reads "Input open (Exclusive,
    event-driven): ..., period N (device default | K x device default |
    aligned by the device), buffer N, FIFO target T"; the status shows "[2ch
    int24, event-driven, period N]". If the event mode cannot be set up the
    input falls back to Shared and the status says so (KI-12 report). A dead
    output stream is still detected with capture events arriving: the
    2-second idle check is now driven by the time since the last OUTPUT
    event (one check every 2 s, five frozen checks end the stream), not by
    the Wait timeout alone. ARCHITECTURE.txt section 64.
  • KI-11 FIXED (to be confirmed) - the late-packet margin of one capture
    period in the FIFO target is now added at EVERY ASIO buffer size in
    Shared mode (and for the loopback source and the event-driven Exclusive
    capture), not only when the buffer is shorter than the capture period.
    On 0.9.11 a 512 buffer with a 441-frame period had no margin, a 512
    block consumed the FIFO down to about 390 frames and one late packet was
    an underrun (22 underruns / 46 discontinuities in 85 s on the same system
    where 256, with the margin, was clean). The reported input latency in
    Shared mode grows by one capture period at every buffer size (about
    10 ms at 44.1 / 48 kHz with the Windows engine; 0.9.11 had it below one
    period only), to be confirmed by block AB; a later version may make the
    margin adaptive (ROADMAP.txt).
  • Diagnostics for the capture path, second round: the "Capture:" line of
    "Copy status" now ends with "max FIFO fill N (now M) frames, max gap:
    wake X ms, read Y ms". "now" is the fill after the last drain (the plain
    copy path keeps whatever backlog it once received, so the real input
    latency can exceed the reported one until the stream restarts: a large
    steady "now" shows that). "wake" is the longest interval between two
    output wake-ups of the audio thread, "read" the longest interval between
    two drains of the main input: a large wake gap with discontinuities
    means the audio thread was held (the host's callback, the system), a
    small one with discontinuities means the capture engine glitched by
    itself. Both are QueryPerformanceCounter differences kept as atomics (the
    audio thread still never logs or traces). The Stats trace event carries
    the three new values (CaptureFifoFillNow, WakeGapMaxUs,
    CaptureReadGapMaxUs; 25 fields, 440 of 512 metadata bytes, checked by
    tests/trace_test.cpp).
  • Counters exclude the first second: one second after the stream starts
    (the output wake-ups of one second) the audio thread requests the same
    clearing as the panel's "Reset counters" (every statistics counter:
    inputs, the Capture line, the gap counters, output glitches, timeouts,
    DSP load max) once (independent review R2). The start-up transient
    (priming, the host's first callbacks, the capture engine settling)
    counted 1 underrun / 2 discontinuities in the first 85 wake-ups of an
    otherwise clean run and had to be explained in every report.
  • Documents: KNOWN-ISSUES.txt KI-11 / KI-13 (status, the 0.9.11
    measurements, the fix, the known limit); ARCHITECTURE.txt sections 61
    (updated) and 64 (new); CODE-REVIEW.txt "0.9.12" and "Independent review
    of 0.9.12" (1 HIGH, 2 MED, 6 LOW, all fixed); TEST-GUIDE.txt block AB
    (AB7: the gap counters; 0.9.12 is validated by AB1-AB4); ROADMAP.txt.
  • Version number: getDriverVersion() returns 9120.
    Not changed: the output path, the converters, the Shared capture path
    (still polled from the output wake-up and between callbacks), the panel
    layout, the installer logic, the tools, the CI workflows.

0.9.11 (changes from 0.9.10) - "Inputs"; fixes from the first recording test
0.9.12 (event-driven Exclusive capture; late-packet margin at every buffer
size; timing counters). Recording in Exclusive mode: use buffer 512 or
larger on 0.9.11.
Summary of all changes:

  • KI-13 (NOT fixed; see the note below) - input drops in Exclusive mode at small buffers. With the
    manufacturer's driver, Exclusive mode, 44.1 kHz, ASIO buffer 256: the
    input counted about 10 drops per second (no underruns) and the recording
    was unusable; at 512 it was clean. Cause: the overfill limit of the
    input FIFO (bufSize2 + target3 = 2048 frames) did not take the capture
    buffer into account. A polled Exclusive capture client (1536 buffered
    frames here, period 256) can hand over everything its buffer holds in
    one call when the audio thread was late for a period or the device
    delivers in bursts; that backlog is real audio, but it crossed the limit
    and was discarded (fill - (bufSize + target) frames, about 35 ms, each
    time). The three overfill limits of pullSource now include the whole
    capture buffer (in ASIO frames for converted inputs); the FIFO capacity
    grew accordingly (capture buffer x4 + target x6 on top of the base).
    Drops are now reserved for a real surplus (a capture clock faster than
    the output's without drift correction, or callbacks stopped for a long
    time).
  • KI-11 PARTLY FIXED (256 clean; 512 still fails, see the note below) - input underruns and discontinuities in Shared mode at small
    buffers. Shared mode (IAudioClient3), output at 48 kHz, input at 44.1 kHz
    (capture period 441 frames, FIFO target 882), ASIO buffer 256: 8
    underruns and 27 discontinuities in 30 s (audible dropouts in the
    recording); 512 clean. Two causes, two changes: (a) with a buffer shorter
    than the engine period the host runs two or more callbacks per wake-up,
    and while they ran the capture buffer (about two periods in Shared mode)
    could overflow, so Windows dropped packets and flagged discontinuities;
    the audio thread now drains the capture clients again after every host
    callback of a wake-up, not only at the start of it. (b) one late capture
    packet (the Windows engine delivers with up to one period of jitter) left
    the FIFO short for the second callback: when the ASIO buffer is shorter
    than the capture period, the FIFO target now includes one more capture
    period (at 256 with a 441-frame period: +10 ms of reported input latency,
    logged as "FIFO target +441 frames (late-packet margin)"; 512 and larger,
    and Exclusive captures with the period equal to the buffer, are
    unchanged; the Loopback source gets the same margin).
  • KI-12 - silent fallback from Exclusive to Shared now explained. With a
    device whose own driver (or the Windows "Default format") fixes the rate
    at 48 kHz, Mode=Exclusive at 44.1 kHz fails ("no format accepted at
    44100 Hz") and the driver runs Shared; the panel's Mode combo said
    Exclusive while the status said Shared, with nothing in between. The
    status line now reads e.g. "Active mode: Shared (Exclusive not
    available at 44100 Hz; the device is fixed at 48000 Hz by its own driver
    or the Windows default format)" (or "(Exclusive refused, hr=...)" when
    the reason is another error, "(Exclusive: no format accepted at
    44100 Hz)" when no reason is known), the bottom bar of the panel shows
    "Exclusive not available, running Shared" in amber, the log names the
    device's shared-mode rate, and FAQ 21 explains what to do. When only the
    input could not open Exclusive, the note follows the input's name and the
    bar says "Exclusive input not available, input runs Shared". Opening
    Exclusive at the device's fixed rate with internal conversion is planned
    for 1.0 (ROADMAP.txt).
  • Diagnostics for the capture path (KI-13): the audio thread keeps six
    counters per input (plain atomics, no tracing from the audio thread):
    pulls, pulls that found no packet, pulls that found two packets or more,
    largest packet, most frames delivered by one pull, highest FIFO fill
    after a pull. "Copy status" prints them in a new line ("Capture: pulls
    ... max FIFO fill ... frames", only with an input) and the ETW "Stats"
    event carries them (CapturePulls, CaptureEmptyPulls,
    CaptureMultiPacketPulls, CaptureMaxPacket, CaptureMaxPerWake,
    CaptureMaxFifoFill). "Reset counters" clears them.
  • Control panel: the "Apply" button is now "Apply and Close" (five
    languages): it saves, applies and closes the panel in one click when the
    changes are live or the DAW restarts the driver (0.7.0 to 0.9.10 kept the
    panel open after Apply; "Close" still discards unapplied changes). When
    something must be read first (the changes apply at the next driver load,
    nothing applied because the DAW holds no driver instance, a host-profile
    mapping saved) the panel stays open and shows it, as before. Enter
    presses this button. The button is wider (170 px) so no translation is
    shortened.
  • Status report: the DSP line printed "Resampler: Hermite" (the kind of
    drift-correction resampler, even when drift correction was off) next to
    an Engine line that said sinc or soxr. It now prints "Rate conversion:
    soxr HQ / sinc / Hermite / none" (the engine that converts the main
    output) and, only while drift correction is active, "Drift resampler:
    sinc / Hermite".
  • FAQ 22: the input level is very low in Shared mode (the Windows input
    volume of the device, found at 1 % on a real system; Exclusive mode
    bypasses it). FAQ 23: an interface with two inputs appears as one stereo
    "Line" endpoint (split it with mono buses in the DAW).
  • Documents: KNOWN-ISSUES.txt KI-11, KI-12, KI-13; ARCHITECTURE.txt
    sections 61-63; CODE-REVIEW.txt "0.9.11" and "Independent review of
    0.9.11" (1 MED, 5 LOW, all fixed); TEST-GUIDE.txt blocks AA
    (0.9.10 soxr / trace folder, now with the results) and AB (recording
    with an interface: Shared and Exclusive, 256 and 512); README and
    COMPATIBILITY (Steinberg UR22mkII tested, inputs, Shared and Exclusive).
  • FAQ 14, COMPATIBILITY, KNOWN-ISSUES KI-1: current DaVinci Resolve
    versions offer I/O Engine = "System Audio" (Windows audio without ASIO),
    so this driver is optional for Resolve.
  • Version number: getDriverVersion() returns 9110.
    Not changed: the output path, the converters, the installer logic, the
    tools, the Arm64X build, CI.

This package contains WasapiDriverARM64X.dll (Setup and bin.zip): on Windows on Arm the Setup registers it once for native ARM64 and emulated x64 hosts. Not yet tested on real Windows on Arm hardware (KNOWN-ISSUES.txt KI-9).