Repository navigation
Releases: irregbex/WASAPI-Driver-for-ASIO
Release list
WASAPI Driver for ASIO 0.9.15
0.9.15 (changes from 0.9.14) - "Start order"
- Fix of a regression of 0.9.14 found by the automatic host test on a real
interface (Steinberg UR22mkII, Yamaha Steinberg USB Driver, Exclusive,
44.1 kHz, input selected, buffer 256): T2 counted 1000 callbacks of 1723
in 10 s (one every 10.00 ms instead of 5.80 ms, 43 overloads); T4 failed
at 64/128/256 and T5 at 44100, while 512, 1024, 48000 and 96000 (where
the input falls back to Shared, no gate) passed. Cause: 0.9.14 started
the OUTPUT stream before the capture stream when the main input was
gated (independent review MED-1); with that driver the render events
then follow the capture period (10 ms). 0.9.15 starts the streams in the
order of 0.9.13 (capture first, then output) on every path and arms the
gate's base on the output clock AFTER both streams started, which keeps
the running-clock base that MED-1 wanted. - Version number: getDriverVersion() returns 9150.
Not changed: everything else of 0.9.14.
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).
WASAPI Driver for ASIO 0.9.14
0.9.14 (changes from 0.9.13) - "Capture gate on the output clock"
Block AB on 0.9.13 (2026-10-25, same system: Steinberg UR22mkII, Yamaha
Steinberg USB Driver, Windows 11 x64, Cubase 15, 44.1 kHz): Exclusive 256
still dropped (384 drops) and the gate refused NOTHING (gated 0): pulls
6527 in about 38 s (172 per second, the output's rhythm), one 441-frame
packet at every drain. The IAudioClock of that driver's CAPTURE stream
advances at the same false rate as its packets (441 frames per 5.8 ms),
so a gate on that clock lets everything through. Shared 256: 0/0/0;
Shared 512: 6 underruns / 19 discontinuities with a maximum read gap of
11.5 ms (the audio thread read on time; the discontinuity flag is set by
Windows' own capture engine when IT lost data from the device driver;
intermittent: the 0.9.12 run gave 0/0/0). The output path is unchanged.
Summary of all changes:
- KI-13 (to be confirmed by block AB on real hardware): the capture gate's
reference is now the OUTPUT stream's IAudioClock when the Exclusive
input runs on the same device as an Exclusive output with a usable clock
(one device, one clock; the output plays with 0 glitches, so its
position is real time), converted to device frames like the output's
glitch detection, base taken right after Start. On another device, or
with a Shared output, or without a clock, the system timer (QPC credit,
as in 0.9.13). The capture stream's own clock is no longer used, and
the stall detector that depended on it is gone. The rest of the gate is
unchanged (7/8 period threshold, one packet per opening unless a real
backlog exists, 4-period bound, backwards-position resync, timer credit
bounded to [-2, +4] periods). - KI-11 note: with an interface that has its own driver, Shared mode at
512 can show discontinuities flagged by Windows' capture engine although
the driver reads on time (max read gap 11.5 ms at a 10 ms period); it is
intermittent and comes from the device side. Recording with such an
interface: use Exclusive mode (no Windows engine in the path). With the
Microsoft class driver at 512 the same test was 0/0/0. - Status: "gated N" unchanged; Stats trace event: CaptureGateRef (0 none,
1 output clock, 2 system timer) replaces CaptureClockFallback (27
fields). Log: "capture gate on the output stream's clock (same device)"
or "... on the system timer (...)" at open, "stop: input capture gate:
pulls=N gated=M clock=output|qpc|none" at stop. - Documents: KNOWN-ISSUES.txt KI-11 (note), KI-13 (0.9.13 results, 0.9.14
fix); ARCHITECTURE.txt section 65 (rewritten); CODE-REVIEW.txt
"0.9.14"; TEST-GUIDE.txt block AB (0.9.13 results, AB7 for 0.9.14);
ROADMAP.txt (0.9.15: plain FIFO re-centring, output glitches counted at
an engine restart, control panel z-order when the DAW is re-activated). - Version number: getDriverVersion() returns 9140.
Not changed: the output path, the Shared capture path, the converters,
the installer logic, the trace provider, the panel apart from the status
text.
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).
WASAPI Driver for ASIO 0.9.13
0.9.13 (changes from 0.9.12) - "Capture gate"; one period per period
Block AB on 0.9.12 (2026-10-25, Steinberg UR22mkII, Yamaha Steinberg USB
Driver, Windows 11 x64, Cubase 15, 44.1 kHz): Shared 256 and 512 clean
(KI-11 confirmed fixed); Exclusive 256 still dropped (427 drops, 13
discontinuities): with that driver every drain, 172 per second at the
output's rhythm, found a full 441-frame packet, 1.73 times real time, and
the capture event did not mark real periods either. Only the stream's
clock told the truth. The output path is unchanged.
Summary of all changes:
- KI-13 FIXED (to be confirmed by block AB on real hardware) - the CAPTURE
GATE. An Exclusive capture is drained only when the capture stream's own
IAudioClock says a whole new period exists since the frames already
accepted, and never more than that: exactly one period per period,
whatever the driver reports and however often the audio thread asks
(ARCHITECTURE.txt section 65). Without a usable clock (missing,
failing, frozen for 20 drains) the gate runs on the system timer for the
rest of the run. Shared and loopback sources are not gated (the Windows
engine reports its packets correctly). - Exclusive capture period: the smallest multiple of the device's default
period that is >= HALF the ASIO buffer (0.9.12: the whole buffer). 512
at 44.1 kHz: 441 frames, reported input latency about 41 ms (0.9.12:
882 frames, 63 ms); 1024: 882. - Status: the Capture line ends with ", gated N" (drains refused by the
gate); Stats trace event: CaptureGated, CaptureClockFallback (27
fields). Log: "capture gate on the stream clock (frequency F)" at open,
"stop: input capture gate: pulls=N gated=M clock=device|qpc" at stop. - Documents: KNOWN-ISSUES.txt KI-11 (confirmed), KI-13 (0.9.12 results,
0.9.13 fix), two observations for 0.9.14 (output glitches counted at an
engine restart; plain FIFO backlog); ARCHITECTURE.txt sections 64, 65;
CODE-REVIEW.txt "0.9.13"; TEST-GUIDE.txt block AB (0.9.12 results, AB7
for 0.9.13); ROADMAP.txt. - Independent review of 0.9.13: 2 HIGH, 3 MED, 4 LOW, all fixed
(CODE-REVIEW.txt): gate decision before reading, timer credit paid back,
clock base armed at Start, backwards / unbounded positions handled,
refused drains counted as pulls. - Version number: getDriverVersion() returns 9130.
Not changed: the output path, the Shared capture path, the converters,
the installer logic, the trace provider, the panel apart from the status
text.
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).
WASAPI Driver for ASIO 0.9.12
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...
WASAPI Driver for ASIO 0.9.11
0.9.11 (changes from 0.9.10) - "Inputs"; fixes from the first recording test
The first test with an audio interface that has inputs (a Steinberg
UR22mkII on Windows 11 x64 with Cubase 15, recording a microphone while a
song played) found three input-path problems that playback-only testing
could not show. The output path is unchanged (0 output glitches in every
run of that test); only the input side and the control panel changed.
Summary of all changes:
- KI-13 FIXED - 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 FIXED - 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).
WASAPI Driver for ASIO 0.9.10
0.9.10 (changes from 0.9.9) - "soxr"
Optional higher-quality rate conversion with the SoX Resampler library,
requested by the maintainer (the default stays the low-latency sinc of
0.9.9), plus build and CI maintenance.
Summary of all changes:
- "Stop trace.bat" now always saves the trace in
C:\Users\Public\Documents\WASAPI Driver for ASIO\Traces and opens that folder in Explorer.
The 0.9.9 "signed-in user's Desktop" detection proved unreliable on a real system (standard
user + different administrator account at the UAC prompt: the file went to the
administrator's profile). Verified on Windows: the 0.9.9 trace contained 556 events of the
WASAPIDriverForASIO provider, decoded by tracerpt, with no user or computer names. - New optional engine for the internal fixed-ratio rate conversion (used
when the DAW rate differs from the device rate with "Low latency" on, e.g.
a 44.1 kHz project on a 48 kHz device, outputs and inputs), used only when
"soxr (best quality, +8-10 ms)" is selected: soxr, the SoX
Resampler library 0.1.3 (Steinberg built-in ASIO Driver 1.0.9.26 installs
soxr.dll next to asiobtin.dll, and asiobtin.dll loads it for sample-rate
conversion (its binary contains the message "Cannot load soxr.dll! No
SRC!"); observed by inspecting the installed files), recipe HQ (20-bit, linear phase, pass band to 91.3 % of
the lower Nyquist frequency, no aliasing). Measured at 44.1 -> 48 kHz:
132.6 dB SNR and -136 dB THD+N at 1 kHz (sinc 114.9 / -122.5), -137 dB
THD+N at 18 kHz (sinc -126.5), images -135 dB (sinc -120), pass-band
ripple 0.003 dB; about half the CPU of sinc. Cost: about 8-10 ms more
latency per converted direction at 44.1-192 kHz, more at 16-32 kHz
(look-ahead 429 input frames = 9.7 ms instead of 64 = 1.45 ms at
44.1 -> 48 kHz; 48 -> 16 kHz 15.6 ms, 16 -> 44.1 kHz 26.8 ms), reported
exactly to the DAW (the model measures
the round trip equal to the reported latencies within 0.5 frame). - New setting FixedRatioEngine=Auto|Soxr|Sinc|Hermite (Advanced tab,
"Rate conversion", with a help tip in the five languages; stored in
profiles; the DAW restarts the driver to apply it). Auto (default) and
Sinc: exactly the 0.9.9 behaviour (sinc within the CPU budget, lowest
latency with full anti-aliasing; Auto never picks soxr). Soxr: soxr when
the shared CPU budget allows, otherwise the 0.9.9 rule, and the log says
why soxr was not used. Hermite: Hermite for every up-conversion (lowest latency
and CPU, ~89 dB); down-conversions still use sinc (or Windows). With Auto
the log line is unchanged from 0.9.9 ("Output: rate conversion 44100 ->
48000 Hz, 2 channels: sinc (12 M MAC/s, budget 150 M)"); with soxr it says
"soxr HQ (12 M MAC/s equivalent, budget 150 M)" and the engine line
"internal rate conversion 44100->48000 Hz (soxr HQ, look-ahead 429
frames)"). - Real-time safety: soxr allocates only on the host thread (stream open,
start); the audio thread never makes it allocate (small calls, warm-up,
a FIFO allocator with headroom; tests count 0 allocations); soxr's global
FFT table is sized once per process. Opening a stream with soxr takes
about 10-20 ms for stereo and up to about 150-300 ms for 32 channels (the
warm-up; the 2 s look-ahead probe runs once per rate pair and process,
later opens use its cached result). ARCHITECTURE.txt section 60. - MSVC warning C4244 (wchar_t -> char, from ) in the Arm64X build
fixed: the ASCII copy of a device name used for channel names is now made
by chn::AsciiShadow (ASCII kept, other characters '?') instead of keeping
the low byte of each character, which could also turn some CJK or
full-width characters into '(' / ')' / tab. - Version number: getDriverVersion() returns 9100 (new scheme
major * 100000 + minor * 1000 + patch * 10; the old scheme would have
given 1000 for 0.9.10, the value of 1.0.0). The update check compares
0.9.10 > 0.9.9 numerically (tested). - CI: GitHub actions updated to releases that run on Node 24 (checkout
v7.0.1, upload-artifact v7.0.2, download-artifact v8.0.2; pinned to
commit SHAs); ilammy/msvc-dev-cmd stays at v1.13.0 (latest release, still
Node 20). Linux jobs run on ubuntu-24.04 instead of ubuntu-latest.
download-artifact now fails on a corrupted artifact (digest mismatch). - Build: the soxr C files are compiled by build.sh, build-x86.sh,
build-arm64.sh and scripts/build-arm64x.ps1 (warnings off for those
third-party files only; 0 warnings from src/). The DLLs still import only
Windows system DLLs. tests/run_all.sh builds soxr for fixedratio_test,
which now also compares soxr, sinc and Hermite and counts soxr's
allocations; update_test checks the version scheme; chnames_test the new
ASCII copy. - Documents: THIRD-PARTY-NOTICES.txt section 6 (soxr, LGPL-2.1, source in
third_party/soxr) and the LGPL 2.1 text; COPYRIGHT.txt; installer
notices; ARCHITECTURE.txt section 60; CODE-REVIEW.txt "0.9.10" and
"Independent review of 0.9.10" (8 LOW findings, all fixed);
KNOWN-ISSUES.txt KI-10; TEST-GUIDE.txt block AA; README, FAQ, BUILDING.
Not changed: the drift-correction resampler (ResamplerQuality), Exclusive
mode, extra devices, the tools (they do not contain soxr), the installer
logic.
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).
WASAPI Driver for ASIO 0.9.9
0.9.9 (changes from 0.9.8) - "Arm64X"; no engine change
One driver DLL for every 64-bit host on Windows on Arm, built with MSVC in CI.
Summary of all changes:
- Arm64X DLL (WasapiDriverARM64X.dll): native ARM64 code and ARM64EC code in
one file, as Microsoft recommends for in-process audio components on
Windows on Arm. A native ARM64 DAW runs the ARM64 half; an x64 DAW running
under emulation runs the ARM64EC half (native speed, no emulation of the
driver itself). Built by the "arm64x" job of build.yml (every push) and
release.yml on a GitHub windows-11-arm runner with MSVC
(scripts/build-arm64x.ps1: cl native + cl /arm64EC, link /machine:arm64x,
static runtime /MT). The script checks the image with dumpbin (machine
ARM64X, exactly the four COM exports, no Visual C++ runtime DLL imported)
and always ends with a ::notice annotation (result, machine line, exports,
imported DLLs, SHA-256) that is readable on the public run page without
signing in. Compiler / linker messages are classified: errors (Cxxxx,
LNK1xxx / LNK2xxx) as ::error, warnings (Cxxxx, LNK4xxx) as ::warning
(0.9.9 prep reported linker warnings as errors). LNK4070 fixed (temporary
.def with "LIBRARY WasapiDriverARM64X"); LNK4279 documented as benign
(CODE-REVIEW.txt "0.9.9 MSVC / Arm64X"). - Setup on Windows on Arm: when the package contains the Arm64X DLL (CI and
release builds whose arm64x job passed; makensis -DARM64X=1), Setup
installs it and registers it ONCE in the 64-bit registry view, without
the "ARM64 or x64 DAW" question: native ARM64 and emulated x64 processes
read the same 64-bit view, so one registration serves both. An upgrade
from 0.9.8 or earlier replaces the ARM64 or x64 registration (exactly one
registration remains). 32-bit DAWs keep WasapiDriver32.dll (WOW6432Node).
The uninstaller removes the file. A package without the Arm64X DLL (local
mingw / zig builds, or a release whose arm64x job failed: the release
notes say so) behaves exactly as 0.9.8. ARCHITECTURE.txt section 59. - Portable install.bat: on ARM64 it registers WasapiDriverARM64X.dll when
that file is in its folder (no question); otherwise the 0.9.8 question. - Release: the Arm64X DLL is part of the Setup and of the bin zip (signed
like the other DLLs when signing is configured); the separate
"WasapiDriverARM64X--experimental-unsigned.dll" download is gone.
"build" runs after "arm64x" and uses its DLL only when the job reported
success and the SHA-256 matches. - MSVC portability fixes (found by the first MSVC build; GCC and clang
accepted the code): dll.cpp had preprocessor directives inside the
arguments of the WB_TRACE macro (undefined behaviour in C++, MSVC error
C2121), now the architecture string is chosen before the call and the
ARM64EC half reports "ARM64EC"; panel.cpp had a font field named "small",
which rpcndr.h defines as a macro ("char") under MSVC; renamed fontSmall.
No behaviour change in the mingw / zig builds. - "Stop trace.bat": when it is started already elevated from an
administrator window of another account, the trace is saved on the
Desktop of the user signed in to the Windows session (owner of
explorer.exe in the same session, redirected / OneDrive Desktops
honoured), not in the administrator's profile. "Start trace.bat" /
"Stop trace.bat" titles carry no version number any more. - README restructured: what the driver is, where to get it and the code
signing policy come first. New CODE-SIGNING-POLICY.txt (what is signed,
by whom, roles, privacy; SignPath Foundation applied for). - Documents: KNOWN-ISSUES.txt KI-9 (Arm64X not yet tested on real Windows
on Arm hardware), TEST-GUIDE.txt block Z (Windows on Arm), FAQ entry,
ARCHITECTURE.txt section 59, CODE-REVIEW.txt "0.9.9 MSVC / Arm64X".
Not changed: the audio engine, the x64 / x86 / ARM64 DLLs (apart from the
version number), the tools, the 32-bit registration.
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).
WASAPI Driver for ASIO 0.9.8
0.9.8 (changes from 0.9.7) - "Hardening"; no new user features
Requested by an external review (Windows audio / MIDI engineering): the driver
must withstand untrusted, buggy or malicious data from host applications and
from its dependencies without crashing or compromising the host process, be
covered by fuzz and unit tests that gate every release, and be observable
with TraceLogging. Valid calls and the audio engine behave as in 0.9.7.
Every finding is listed in CODE-REVIEW.txt ("0.9.8 hardening review",
H1-H32); the design is ARCHITECTURE.txt section 58.
Summary of all changes:
- Exception barrier (H1): every function the host or Windows calls (all
IASIO and IUnknown methods, the class factory and the four DLL exports,
every window procedure, hook and enumeration callback, the device and
volume notification callbacks, every thread procedure, the destructor and
the panel's message loop) catches any C++ exception and returns that
boundary's error (ASE_HWMalfunction / ASE_NoMemory, ASIOFalse, E_FAIL /
E_OUTOFMEMORY, DefWindowProc, ...). Contained exceptions are logged (first
16) and traced. The real-time path allocates nothing; the audio thread is
guarded at its thread procedure only (no cost). - Host argument validation (H3, H4, H13-H17): new src/asiocheck.h (pure,
tested offline) with the call-order rules (Created / Initialized /
Prepared / Running) and every argument rule: null pointers, channel
indices, isInput values, numChannels <= 0 or above the channel count,
duplicate channels, buffer sizes outside 32..4096, missing callbacks,
NaN / infinite / negative / non-standard sample rates, clock sources,
future() selectors with a null or wrong argument. Host structures are read
once and copied (the callbacks too), so changing them concurrently cannot
bypass a check. createBuffers checks everything before it disposes the
previous buffers. Return codes that changed: start() before init and
queries before init -> ASE_NotPresent; setSampleRate / controlPanel from
inside a callback -> ASE_InvalidMode; QueryInterface with a null pointer
-> E_POINTER. disposeBuffers (in any state) and setClockSource(0) keep
answering ASE_OK as in 0.9.7. The test tool's private engine-information
selector now needs a header (a 0.9.7 test tool shows no engine line with
this driver). - Use after free (H2, H19): the device and volume notification objects
detach under a lock, so the driver can be destroyed while Windows delivers
a notification; a release on any thread marks the object as dying. - Untrusted device data (H5-H7, H10): device mix formats, periods,
latencies and buffer sizes are range-checked (no write past a frame, no
undefined float-to-integer conversion, no size overflow on the 32-bit
build); at most 256 capture packets are read per wake-up. - No unbounded waits (H8, H9): start() waits at most 10 s for an exiting
audio thread (then handles it as stuck, like stop()); the audio thread
ends with a reset request after 10 s without a render event while the
device position stays frozen (device stalled without a notification; a
device whose position still moves, e.g. right after a resume from Modern
Standby, keeps the stream) and on a failed wait. Every remaining
wait is listed with its bound in ARCHITECTURE.txt 58.4. - config.ini and other parsers (H11, H12, H23-H25): the value parser,
normalization, UTF-16 decoding, profile lists, host profiles and OutputMap
moved to pure headers (src/parse.h, src/cfgtypes.h) and are fuzzed;
fixed an integer overflow (DirectMonitorInput / Output = -2147483648) and
undefined swscanf overflow in OutputMap; temporary file names include the
thread id; the profile-API lists are walked within the reported length. - Data races removed (H18): getSamplePosition's fallback values, the
callback counter and the init flag are atomics. - TraceLogging (new): the DLL is the ETW provider "WASAPIDriverForASIO"
{52b9f111-957d-5973-b76d-97bdf8f813df} (name-hash GUID, never a Microsoft
name or GUID). Events: driver load / unload / create / destroy, init,
every IASIO call outcome (non-real-time threads), device resolution,
stream opening (mode, rates, period, buffer, format, conversion), resets
and reasons, device notifications, errors with HRESULT, contained
exceptions, a 10 s statistics summary (counters only, from the host
thread), crash protection, panel and update-check results. Never audio
data, paths, user or computer names. Disabled tracing costs one atomic
read per event. Encoder: src/tlg.h (Microsoft's TraceLoggingDynamic.h
does not compile with mingw-w64, see ARCHITECTURE.txt 58.7). - Tracing kit: trace/WasapiDriver.wprp (own EventCollector and buffer budget
for the driver at level 5; Microsoft-Windows-Audio at level 4 in a
separate collector; memory and file profiles), "Start trace.bat" (color
B1) and "Stop trace.bat" (color E1), and TRACING.txt (how to record,
what is and is not recorded, how to attach it to a GitHub issue). The
Setup installs them in "Tracing" with Start menu shortcuts; the release
folder has them in Tools. PRIVACY.txt describes tracing. - Tests: tests/run_all.sh runs all 18 offline tests; new fuzz_test (180000
deterministic iterations over every parser of untrusted data),
asiocheck_test (validation rules, 200000 random host calls, read-once
property) and trace_test (SHA-1, name-hash GUID, exact event bytes), all
with AddressSanitizer + UndefinedBehaviorSanitizer + libstdc++
assertions. WasapiDriverTest.exe: new T11 "Bad host calls" (invalid
arguments and wrong order against the real driver, no audio; runs right
after T1 so every later test shows the driver survived). - CI: build.yml runs tests/run_all.sh; release.yml has a "tests" job that
every other job needs, so nothing is built, signed or published unless all
tests passed. - Dead code removed (H32): unused interface strings S_ABOUT and
S_STATUS_TITLE (5 languages), WasapiBridge::recommendedBuffer, the
never-read member monWas, a duplicated null check in getClockSources,
KnownRate and the swscanf OutputMap loop (replaced); duplicated helpers
now exist once in parse.h. - Portable install.bat / uninstall.bat colors 4A / 8B.
- Independent review of 0.9.8 (CODE-REVIEW.txt R1-R7, all fixed):
getErrorMessage copies only the message and its terminator again;
disposeBuffers and setClockSource(0) are lenient as in 0.9.7; the stall
detection checks that the device position is frozen; install.bat,
uninstall.bat, "Start trace.bat" and "Stop trace.bat" check administrator
rights with fltmc, relaunch themselves elevated only once (marker
argument) and the trace helpers treat any non-zero wpr result (HRESULTs
are negative) as a failure; "Stop trace.bat" saves to the signed-in user's
Desktop (decided before elevation) and prints the full path; the update
worker's trace event is inside its exception barrier; comment fixes.