Repository navigation
WASAPI Driver for ASIO 0.9.12
Pre-release0.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).