Skip to content

Releases: irregbex/WASAPI-Driver-for-ASIO

WASAPI Driver for ASIO 0.9.15

Pre-release

Choose a tag to compare

@github-actions github-actions released this 26 Oct 02:06

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

Pre-release

Choose a tag to compare

@github-actions github-actions released this 26 Oct 01:44

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

Pre-release

Choose a tag to compare

@github-actions github-actions released this 26 Oct 00:43

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

Pre-release

Choose a tag to compare

@github-actions github-actions released this 25 Oct 19:41

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...
Read more

WASAPI Driver for ASIO 0.9.11

Pre-release

Choose a tag to compare

@github-actions github-actions released this 25 Oct 18:15

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

Pre-release

Choose a tag to compare

@github-actions github-actions released this 23 Oct 19:08

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

Pre-release

Choose a tag to compare

@github-actions github-actions released this 21 Oct 13:45

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

Pre-release

Choose a tag to compare

@github-actions github-actions released this 20 Oct 12:25

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.