This build runs inside a browser tab. Everything a measurement needs - the generator, the oscilloscope, the FFT analyser, the sweeps - is the same code as the desktop application, but the bottom of the stack is not: a page cannot open a sound card the way a native program can. This chapter is the short list of what follows from that, and it is worth reading once before you trust a number.
The reason is that the app depends on audio interfaces only Chromium implements - frame-accurate probing of the real capture rate, and the AudioWorklet form it uses to receive samples. Rather than start and then fail in confusing ways halfway through a measurement, the app checks the engine before it builds anything and refuses cleanly.
Note the scope: this is about the whole application. Missing WebUSB costs you only the QA40x backend; the wrong browser costs you everything.
Web Audio is the default backend and the one you get with an ordinary sound card. Capture comes in through the browser's microphone/line-in permission and playback goes out through the browser's audio output.
The app asks for the device you selected exactly, in stereo, and explicitly switches echo cancellation, noise suppression and automatic gain control off, so nothing the browser offers for voice calls is applied to your signal. If the device refuses the rate that was asked for, the app retries without the rate constraint but still pinned to that device - it never quietly substitutes a different one. Anything else surfaces as a visible error rather than a recording of the default microphone.
Samples reach the page as float32, downstream of the Windows shared-mode mixer. There is no integer word whose width you could choose, which is why Preferences ▸ Audio shows Device, Sample rate and Card for Web Audio and no Bit depth control at all. It is not hidden - it does not exist on this path.
The app opens the stream first, reads the rate the browser actually granted and then builds its audio graph at that rate, so the two can never disagree. What it cannot do is change the rate: that is the device's Windows shared-mode format, and it is set in Windows. The full procedure - including the fact that you must reload the tab afterwards so the device is re-opened - is on its own page: Configuring the Windows input device. Read it before your first measurement; a card left at 48 kHz analyses a band that stops at 24 kHz however long an FFT you choose.
The QA40x backend drives a QuantAsylum QA402 / QA403 directly over WebUSB, with no operating-system audio path in the way at all. Its row appears in the backend list only when the browser exposes WebUSB; when it does not, the row is still shown, disabled, carrying its reason - Requires WebUSB over https:// or localhost - works in Chrome; other Chromium browsers may not expose it - so its absence is explained rather than mysterious.
What has to be true before an analyzer can be used:
https:// with a valid certificate, Edge, Opera and
Brave did not reach the analyzer. Being built on Chromium is not enough
- a browser also has to expose WebUSB and let a page use it, and those
three do not, at least as they ship. If the QA40x is what you came for,
use Chrome.https:// or from localhost.Only one analyzer may be attached at a time. The claim is exclusive: the app takes interface 0, so the QA402 / QA403 must not be open in the QuantAsylum software or in another tab. A claim that fails leaves the device closed rather than half-owned.
Since Web Audio is downstream of the mixer, the QA40x is the only bit-exact backend on this machine: its samples cross USB as 24-bit values in 32-bit words and never enter an operating-system audio path at all. The other bit-exact option is not on this machine - it is a bench, where the desktop application opens a card in exclusive mode on your behalf.
A Phonalyser server does not only serve its sound cards - it also serves this application. Ask a bench for its address in a browser and you get a copy of Phonalyser.web that is already pointed at that bench: it dials its own server automatically, before the first device scan, so the machine you loaded it from is connected by the time you open Preferences.
That page offers the bench's backends and nothing else. There is no
Web Audio row and not even the disabled QA40x row. This is honesty, not a
restriction: such a page arrives over plain http:// from a
machine on your network, which is not a secure context, so
getUserMedia and WebUSB genuinely do not exist on it.
Offering a local backend there would be offering a choice whose every open
must fail, and a greyed row would only invite the question "why can I see
it".
If a backend you had selected earlier is no longer offered, the page says so plainly rather than failing somewhere deep in the browser. A backend remembered from a bench, on the other hand, is never migrated away: its row is restored before its server has answered, so the device, rate and card you had set on that bench survive a reload.
https:// through a TLS reverse proxy is
recognised exactly like one reached directly, and the session it opens is
encrypted to match. A bench that answers too slowly, more than about half a
second, is the one case that goes unrecognised: the page then comes up with
the full local backend list, which is not wrong - an https://
page is a secure context, so Web Audio and the QA40x really do work
there.A bench session is a plain ws:// WebSocket. A browser refuses
to open one from a page it loaded over https:// - the
mixed-content rule - and it refuses before anything is dialled, so
there is no timeout to interpret. The app tells you by name instead of
leaving you to guess.
Loopback is exempt, so from an https:// page you can still
reach a bench at localhost, 127.0.0.1 or
::1 - but not one anywhere else on the network. There is no
setting that changes this. The supported route is the one above: load
the application from the bench itself, where the page and the session
share the same plain http:// origin and the rule never
applies.
On the ordinary https:// page in Chrome or Edge, Save
opens a real Save-as dialog and the file goes where you put it. On a page
served by a bench - which arrives over plain http:// - that
dialog does not exist. The browser downloads the file to your
download folder under the suggested name instead, without asking, and the
app reports it saved as soon as the download starts rather than when it
finishes. If a file of that name is already there the browser quietly
writes name (1).wav, and the app cannot see that it did.
Opening files behaves the same way on both kinds of page: you get a file chooser, cancelling really cancels, and the name you picked is the name that is used.
Settings and card profiles are kept in the browser's local storage,
not in files on disk. Two things follow. They are per browser and per
site: clearing this site's data discards them, and they do not travel
to another browser or another machine. And a stored value that will not
parse is never silently replaced - it is copied aside under the same key
with a .corrupt suffix and the run starts from defaults, so a
damaged document can still be read back out with the browser's developer
tools instead of being overwritten by the next save.
Both documents can be opened and edited as text from Tools ▸ Preferences / Devices - see Editing the settings as JSON. That is also how you copy a calibration to another browser or another machine, which matters here precisely because browser storage does not travel: open the store, copy the document, paste it into the same window on the other machine.