Phonalyzer for QA40x

Phonalyser is a free, open-source (AGPLv3) audio analyzer for Windows / Linux / macOS (soon), aimed at electrical audio-device measurement — no acoustic path — and specifically at the low-THD end where ordinary tools run out of floor. It grew out of a frustration: once you’ve built a good notch and a quiet ADC, the routine of pushing the fundamental through the notch and hand-correcting each harmonic for the notch’s attenuation and phase is tedious and error-prone, and the noise floor often sits right where the interesting harmonics live. I wanted a tool that removed both problems.

Its available on: GitHub - dgo42/Phonalyser: Universal precise audio measurement software · GitHub

On DIYaudio Phonalyzer is presented: Phonalyser — open-source audio analyzer with coherent averaging + FLL (Win/Linux/Mac) | diyAudio

I can confirm it’s working with a QA403. It’s an interesting development.

2 Likes

Thank you for promoting Phonalyser :slight_smile:

1 Like

The latest version certainly looks like it has a lot of potential. Well done. I am continually amazed at the skill level of programmers- way in excess of anything I could even dream of. :slight_smile:

I have a few questions @dgo42 as I must have missed a few things

Where are the input range settings for the QA403 and is there an autorange option?

It also appears the attenuators/dividers on the generator side are not working and the input attenuators are not working either. Am I missing something?

Can the software always trigger the attenuator when exiting the program and illuminate the Atten light? This is important for protecting the QA403 from excess inputs when the software is not running.

And I often use the 384kHz sampling rate for (A/D only) to perform FFTs up to 150kHz or more. Can that option be enabled?

When zooming into a plot, how do you zoom back out without going back to the default autoscale? How do I set the vertical range to the scale I want (like +/- 0.5dB etc)?

Thank you very much :flushed_face:!

Under menu Tools → Preferences in Preferences dialog open Audio tab:

And there you can select input attenuator and scrolling down - output level.

This app was developed first for use with arbitrar (or even exceptional) sound card using standard windows sound APIs. But after publishing in thread on diyAudio multiple users has asked for QA40x support. I don’t have any, but user has dropped links to multiple open source projects adopting QA40x protocol like ASIO401 or Python scripts from QuantAsylum. After analysing this projects I have compiled document QA40x-protocol (in Phonalyser GitHub) and implemented HW protocol simulator based on open information. First I have tested it with genuine QA40x software and then testet my app using this simulator. It implements only USB side protocol and has between “DAC” and “ADC” paths digital loopback which adds TPDF dither on 23 bit for realistic noise floor.

I would like to implement input guard by exiting app/switching to other ausio backend, but I need to know how to do it? Simple select highest attenuation or set unused value, I don’t know.

Multiple users has already asked for I2S support, you asked for 384kHz support. Again I would like to implement it but I don’t know how.

There is multiple possibilities to zoom&pan the plot (it works equal in all plots)

  • You can use mouse wheel to vertical move, wheel + shift for horizontal. And if you add ctrl - you can zoom in both directions respectivly
  • There is also rubberband zoom - if you select some rectangular region using mouse click → drag → release mouse button, then selected region will be enlarged to entire view size. There is also zoom stack. I.e. if the view is active (mouse cursor is in the view) or you have selected view clickin on it you see green border - you can click crtl + z and redo rubberband zoom backwards to initial zoom
  • There is also autosetup button on the top left corner of the view image It tries to zoom trace for maximal details. In FFT view on horizontal axis it selects fundamental ± decade. For 1 kHz for example it shows 100 Hz - 10 kHz. Vertical adds 20dB on top of fundamental and -20dB from noise floor.
  • In FFT & FreqResp there is also maximize button image which maximize horizontal axis and adds +30dB on the top of fundamental and -30dB below noise floor

Currently there is no possibility to define exact vertical/horizontal range, but it’s easy to add.

Incredible response, so amazing.

I will definitely explore the tools-preferences part.

So the output signal (generator) also takes into account the control of the attenuators? Reason being, at low and very low levels, you want an attenuator derived signal from a high level D/A output. That reduces the distortion in the generator signal massively. I will experiment (and test with a dedicated THD analyser) with the generator levels to see how you have implemented them.

I will explore the functions you have explained- thank you. I’m sure this must have taken many hundreds of hours to achieve. I am in awe of this. :slight_smile:

1 Like

Hey @dgo42

Just in case you missed this:

Input protection / 42 dBV: switching the input full-scale is a single register write on bulk EP1 OUT — a 5-byte frame [reg][value as u32 big-endian]. Register 0x05, index 7 selects the 42 dBV range (indexes 0–7 → 0/6/12/18/24/30/36/42 dBV):

05 00 00 00 07
Both the official app and ours (qa40x-rs) write this at startup and again when exiting: since 42 dBV is the least sensitive range (maximum attenuation), it leaves the analyzer in a safe state — whatever is present at the input when the next session opens can’t overload a sensitive range. Note it drives mechanical relays, so allow a short settle time after writing it.

384 k at the USB level: the sample rate is register 0x09, written the same way, with an index rather than Hz — 0/1/2/3 → 48k/96k/192k/384k. So 09 00 00 00 03 selects 384 ksps (QA403 only). Nothing else is needed device-side; streaming then runs at that rate.

Since you’re developing without hardware access: I maintain virtual-qa40x, a simulator of what the QA402/QA403 does on the wire. It exposes a fake device over USB/IP that both the official app and mine recognize as a real unit, so you can test your full stack against it: register bus, streaming (with a calibrated loopback and configurable noise/distortion), and even the firmware-flash flow (it emulates the bootloader handshake). It also has a --record option that logs every USB exchange, decoded, to a readable file — handy for answering “what does the QuantaSylum app actually send?” questions like these.

Links to the different projects:

The simulator: GitHub - GarageDeveloper/virtual-qa40x-rs: Virtual QA402/QA403 audio analyzer over USB/IP (unofficial, not affiliated with QuantAsylum) · GitHub

Notes regarding the protocol: qa40x-rs/doc/device-notes.md at main · GarageDeveloper/qa40x-rs · GitHub

HTH,

Raph

2 Likes

Hi @raph29

Thank you, I have already implemented for the next version.

Does it simple switch to 384k? Why then genuine software disables this button? :thinking:I will try in the next version.

I have already developed libusb mock library with QA403 mock support, but then I have implemented HW simulator based on NXP RT1062 eval.board. I use digital loopback with sample rate simulation (check if sample rate corresponds realt stream speed) and TPDF dither for noise floor simulation and first get it worked with genuine QA40x software. NW simulator as also virtual COM port and I can see the protocol in realtime. So I can also see which register are writen readed.

But thank you for proposition! I’ll take a look on it.

P.S. can your simularo work with genuine app?

1 Like

@raph29 do you know how to control I2S extension port?

yes it does. That’s my point. By using it you can spy what the official app does without having the hardware. The help → about works, the firmware flash works, the stream works. For sure there are limitations but it was quite helpful for my own developments.

I’m mostly on mac and I launch the server on my mac, I start a windows vm with the genuine app and usbip-win32 installed and pointing to my mac IP address and voilà, the app see a qa403 or qa402 depending on the way you start it. The simulator should work on linux and windows although I did not try the builds you can find in the release page of the project.

If you are on windows it should be something like that:

  1. Get the server: download vqa40x-v0.4.0-x86_64-pc-windows-msvc.zip (or aarch64 for ARM PCs) from the Releases page, and unzip it anywhere.
  2. Start it:
    vqa40x.exe --model qa403
  3. Allow it through the Windows Firewall prompt if you’ll attach from another machine (it listens on port 3240). Useful extras: --serial AB12_CD34 for a stable identity,
    –record session.jsonl to log every USB exchange.
  4. Install the USB/IP client: usbip-win2 (its installer sets up the vhci driver; reboot if asked).
  5. Attach the virtual device (same machine or any other Windows PC on the network):
    usbip.exe attach -r 127.0.0.1 -b 1-1
  6. Replace 127.0.0.1 with the server’s IP when attaching remotely. WinUSB binds automatically (the device ships MS OS 2.0 descriptors) — no Zadig, no INF.
  7. That’s it: the QA40x genuine app, qa40x-rs, or your own software now sees a QA403 as if it were plugged in — register bus, calibrated loopback streaming, telemetry, and the
    firmware-flash flow all work. During a firmware-update test the device “reboots” twice; run tools/auto-attach.ps1 to re-attach automatically, like real hardware re-enumerating.

Only Matt and his team can answer that. They consider it experimental as far as I know. Maybe they need to adjust stuff in the firmware or in their calculation I don’t know.

I’ve just finished to add this to the simulator based on pcap analysis with an AI, at least the genuine app looks good with it. It’s in release 0.5.0 of virtual qa40x. I’m updating my notes with the findings (registers and so on), it will be available in a moment.

Here is the output when the genuine app streams on the virtual qa40x with I2S activated.

 ./vqa40x --model qa403 --record test-i2s.json
[2026-07-24T20:11:03Z INFO  vqa40x] USB/IP server listening on 0.0.0.0:3240 — 1 device(s)
[2026-07-24T20:11:03Z INFO  vqa40x]   [1-1] QA403 16c0:4e39 serial 457F_6800 fw v60 (analyzer)
[2026-07-24T20:11:03Z INFO  vqa40x] attach: usbip attach -r <this-host> -b <busid>  (see busids above)
[2026-07-24T20:11:03Z INFO  vqa40x] recording USB exchanges to test-i2s.json
[2026-07-24T20:11:09Z INFO  vqa40x_usbip] device 16c0:4e39 attached (busid 1-1)
[2026-07-24T20:11:12Z INFO  vqa40x_core::analyzer] input range set to index 7 (42 dBV)
[2026-07-24T20:11:14Z INFO  vqa40x_core::analyzer] input range set to index 7 (42 dBV)
[2026-07-24T20:11:14Z INFO  vqa40x_core::analyzer] sample rate set to 48000 Hz (index 0)
[2026-07-24T20:11:19Z INFO  vqa40x_core::analyzer] front-panel I2S started (32-bit frames)
[2026-07-24T20:11:21Z INFO  vqa40x_core::analyzer] output range set to index 0 (-12 dBV)
[2026-07-24T20:11:22Z INFO  vqa40x_core::analyzer] stream stopped: 36864 samples in 0.77 s (effective 47.7 kS/s, nominal 48 kS/s)
[2026-07-24T20:11:23Z INFO  vqa40x_core::analyzer] stream stopped: 36864 samples in 0.77 s (effective 47.9 kS/s, nominal 48 kS/s)
[2026-07-24T20:11:24Z INFO  vqa40x_core::analyzer] stream stopped: 36864 samples in 0.77 s (effective 47.7 kS/s, nominal 48 kS/s)
[2026-07-24T20:11:25Z INFO  vqa40x_core::analyzer] stream stopped: 36864 samples in 0.77 s (effective 47.8 kS/s, nominal 48 kS/s)

However, the only source of truth is Matt and his team. These are just observations.

Cheers

2 Likes

@raph29 thank you for yoyr simulator, I have grabed your register finding to my HW simulator and will publish soon on GitHub too.

I have already ported early Phonalyser as pure web app, running in browser. And now I found possibility to access QA40x from browser (WASM/WebUSB) and this IS CRASY!