• Welcome to ASR. There are many reviews of audio hardware and expert members to help answer your questions. Click here to have your audio equipment measured for free!

Phonalyser: free open-source analyzer - THD, SNR/ENOB, frequency response, scope (+ QA40x support)

dgo42

Member
Joined
Jul 7, 2026
Messages
44
Likes
45
Hi all,

following a suggestion, here is a dedicated thread for Phonalyser - a free, open-source audio measurement workbench I develop. AGPL-licensed, no account, no telemetry; it grew on my own bench and I use it daily.

Links first:
What it is

A desktop analyzer (Windows / Linux / macOS) plus a WebAudio port of the same engine that runs in Chrome/Edge. The modules:

  • FFT analyzer - THD, THD+N, IMD, SNR, N, N+D, SINAD, ENOB with per-harmonic readout; coherent and power averaging with overlap up to 93.75 %; windows from Hann through Blackman-Harris, flat-top, HFT144D/248D, Kaiser and Dolph-Chebyshev; live .frc calibration. With a capable converter (e.g. E1DA Cosmos) sub-ppm THD measurements are practical - coherent averaging pulls the correlated floor down.
  • Oscilloscope - triggered time-domain view with digital-phosphor dense rendering, glitch trigger, and a residual view: captured signal minus a best-fit tone (single or dual), which exposes the distortion, noise and glitches hiding under the fundamental.
  • Frequency response - Farina log-sweep deconvolution, RIAA/IEC and ideal-filter overlays (low/high/band-pass, notch × Butterworth, Chebyshev, inverse Chebyshev, elliptic, Bessel) with measured-vs-ideal compare, and a band-flatness readout (−X dB corners or ± deviation over a range).
  • Signal generator - DDS sine, dual-tone, rectangle/triangle, noise, sweeps; dither depth settable in bits or directly in dBV so it reads straight off the FFT noise floor.
  • DAC pre-distortion - a closed-loop wizard that iteratively cancels the DAC's own harmonics (and dual-tone IMD), pushing the playback chain below what the converter does alone.
  • Notch tuning - a live looping sweep tracks a passive twin-T's null while you trim it, then de-embeds the notch's response from the FFT.
  • Audio paths - WASAPI-exclusive and WDM-KS on Windows, CoreAudio on macOS, JavaSound on Linux - bit-exact, high sample rates, 16/24/32-bit. Plus a native USB backend for the QuantAsylum QA402/QA403 (vendor software closed): always-duplex on the device's single clock, true 24-bit, full-scale taken from the device's own range calibration.
Current release - 1.1.0 (2026-07-21)

Highlights of the last release: the ideal-filter overlay/compare and the flatness readout on the frequency-response module; the scope's residual view and the DSO-grade dense trace rendering; per-card calibration profiles (full-scale follows the physical card across backends, one row per attenuator/DIP range, per-channel L/R values, known-card catalog seeded for Cosmos ADC / I2SoverUSB); the QA40x backend on all three desktop platforms; output-channel selectors; help in English, German and Ukrainian, UI in 31 languages. Full changelog: https://dgo42.github.io/Phonalyser/changelog.html

A look ahead - 1.1.1 (in test now)

The headline is a metrology correction I want to be transparent about. While cross-checking noise numbers against a QA403 I ended up building a ground-truth pipeline (raw WAV capture -> least-squares sine fit and subtraction -> rectangular-window Parseval band integral; script and reference capture are in the repo). The outcome on my side: all integrated-noise metrics (SNR, N, N+D, SINAD, ENOB, THD+N) were pessimistic by the analysis window's noise bandwidth (NENBW) - 1.76 dB with Hann, 3.0 dB with Blackman-Harris 4, up to 7.5 dB with HFT248D. Tones and THD were never affected. 1.1.1 divides the noise integrals by the exact NENBW computed from the actual window table, rescales the integral for the excluded signal zones instead of counting them as silence, and makes the fundamental's skirt exclusion robust at high overlap. Validated against constructed, independently computed dither power; the Theory-of-operation chapter documents the math and tabulates every window's factor. Desktop and web both.

Also in 1.1.1: a fixed 32-bit Windows build (a libusb calling-convention bug crashed QA40x streaming - relevant if your measurement PC is an old lab machine), and the plain JARs become fully self-contained: the WASAPI-exclusive 24-bit mixers, the help and all UI languages now ride inside the JAR and unpack themselves on first start.

I'm happy about feedback, measurement cross-checks and bug reports - here or on GitHub. Screenshots attached below.
Multufunctional tab:
1784802095855.png

FFT: ultralow distortion:
1784802141738.png

Frequency response: 1kHz twin-T notch filter:
1784802196457.png
 
Last edited:
Hi!

Phonalyser looks very promising!

Here's some thoughts...

- Would it be hard to make the THD table units switchable? I'd like to have dB as a unit as well in addition to dBV and percent.
- The output amplitude could be defined as dB as well as an option. It's not straightforward to output for example 0 dBFS signal without calculating the amplitude first. For my case I use 5.91 dBV to get the 0 dBFS signal out.
- It would be good to also have a dBr scale in the FFT view, referenced to the fundamental.
- I couldn't get the FFT-view to the "20 Hz - 20 kHz" view after I pressed the "Auto-setup" or "Maximise" -buttons. You can use CTRL and mouse wheel to scale the y-axis, but is there something similar for the x-axis? Or could there be a "20Hz - to 20 kHz" -button?
- ASIO support could be useful too.

These might be bugs:

- You'll have to enter for example "129" to the "Stop after" -value to stop the measurements to 128 averages.
- THD+N seems to be over 10 dB too optimistic when comparing to MultiTone Analyzer or REW. It would be easier to compare them if all the units could be swithed to (for example) dB.
- I couldn't configure my output device higher than 16 bits when using WASAPI (This could be possible with version 1.1.1...). With JavaSound I was able to use higher bit depth.

And by the way: Using the higher sample rates for the input device makes it easy to study the behavior of DAC filters. This is a killer feature!

Thanks for your efforts!
 
Phonalyser looks very promising!
Thank you!
- Would it be hard to make the THD table units switchable? I'd like to have dB as a unit as well in addition to dBV and percent.
It's possible and relative easy
- The output amplitude could be defined as dB as well as an option. It's not straightforward to output for example 0 dBFS signal without calculating the amplitude first. For my case I use 5.91 dBV to get the 0 dBFS signal out.
Output can be defined in V (nV -> V) and dBV. My approach was to measure by well known amplitude. Using dBFS has IMO narrow usage. What is your exact usage for 0dBFS? (Add dBFS is also not complex)
- It would be good to also have a dBr scale in the FFT view, referenced to the fundamental
It's also possible. It's actually only shift
- I couldn't get the FFT-view to the "20 Hz - 20 kHz" view after I pressed the "Auto-setup" or "Maximise" -buttons. You can use CTRL and mouse wheel to scale the y-axis, but is there something similar for the x-axis? Or could there be a "20Hz - to 20 kHz" -button?
Yes, you can use rubberband zoom (with ctrl-z redo) or wheel + ctrl - horiz. move and wheel + ctrl + shift - horiz zoom in/out. I plan to add dialog to define exact vert./horiz. ranges
- ASIO support could be useful too.
What exact usage do you have? Are some sound cards not supported?


- You'll have to enter for example "129" to the "Stop after" -value to stop the measurements to 128 averages.
Yeah, it's old one I every time postpone
- THD+N seems to be over 10 dB too optimistic when comparing to MultiTone Analyzer or REW. It would be easier to compare them if all the units could be swithed to (for example) dB.
I have found in version 1.1.0 that noise calculation depends on window and already fixed it in 1.1.1. Please test it with rectangular window (0dB offset) and BH4 - 3dB offset. And I have also enchanced fundamental/harmonics lobe's skirt exclusion which can gain additional 0.3-0.8dB (lower noise floor). I need exact comparison. If you use different apps to compare - it is important to use same sample rate/bit width/FFT size/window/average count/average coherence/frequency snap to FFT bin (w/o it power leackage is bigger).
Very important point on noise floor difference: I exclude complete fundamental/harmonic lobe's skirt, because it is not noise - it is power leakage due to generator frequency difference with exact FFT bin, DAC/ADC clock difference, FFT window. See video from Hans Rosenberg:
He has also found, that famous QuantAsylum QA40x measures noise incorrect:
and QuantAsylum has already fixed it in January 2026 in version 1.221. In my app all these aspects have been taken into account.
- I couldn't configure my output device higher than 16 bits when using WASAPI (This could be possible with version 1.1.1...). With JavaSound I was able to use higher bit depth.
Do you use 32 bit windows version? On my main x64 PC I have cards in "EXCL" mode. But maybe it is due to I have different ASIO drivers for my cards. In version 1.1.1 the bug with csjsound library support is solved and such cards should work in "EXCL" mode and 24/32 bit are accessible.
And by the way: Using the higher sample rates for the input device makes it easy to study the behavior of DAC filters. This is a killer feature!
Using WASAPI EXCL mode (do you have it?) is possible to use up to 768kHz. I have no problem with my Cosmos E1DA ADCiso and W-DAC 2. But Cosmos produce +20dB more noise in 768 mode as in 384 mode.
 
Once again, hats off for the developers!
 
I have found in version 1.1.0 that noise calculation depends on window and already fixed it in 1.1.1. Please test it with rectangular window (0dB offset) and BH4 - 3dB offset. And I have also enchanced fundamental/harmonics lobe's skirt exclusion which can gain additional 0.3-0.8dB (lower noise floor). I need exact comparison. If you use different apps to compare - it is important to use same sample rate/bit width/FFT size/window/average count/average coherence/frequency snap to FFT bin (w/o it power leackage is bigger).
Very important point on noise floor difference: I exclude complete fundamental/harmonic lobe's skirt, because it is not noise - it is power leakage due to generator frequency difference with exact FFT bin, DAC/ADC clock difference, FFT window. See video from Hans Rosenberg:
He has also found, that famous QuantAsylum QA40x measures noise incorrect:
and QuantAsylum has already fixed it in January 2026 in version 1.221. In my app all these aspects have been taken into account.

I found the reason why Phonalyser shows better THD+N than Multitone Analyzer or REW.

With my configuration THD+N is -115.9 dB when using 55 (Or less) averages:

1784881316860.png



With 56 (Or more) averages it is -129.1 dB:

1784881503579.png


Noise, Noise + Distortion and SNR are changed too by about 15 dB. The exact number of averages is not always 55 or 56, but approximately that. For example 64 averages show always better (but false) THD+N and 32 averages more realistic one. Both Multitone and REW shows about -119 to -120 dB THD+N, but the 3 dB difference can easily be understood by the difference in parameters.
 
What is your exact usage for 0dBFS?

Not necessarily exactly 0 dBFS, but it would be easier to use the same unit when comparing with Multitone and REW.

What exact usage do you have (*FOR ASIO*)? Are some sound cards not supported?

For example, on the E-MU 0404, the Toslink outputs and inputs are on channels 3 and 4 and cannot be used at all when using WASAPI, only channels 1 and 2.
 
I found the reason why Phonalyser shows better THD+N than Multitone Analyzer or REW.

With my configuration THD+N is -115.9 dB when using 55 (Or less) averages:

View attachment 546802


With 56 (Or more) averages it is -129.1 dB:

View attachment 546803

Noise, Noise + Distortion and SNR are changed too by about 15 dB. The exact number of averages is not always 55 or 56, but approximately that. For example 64 averages show always better (but false) THD+N and 32 averages more realistic one. Both Multitone and REW shows about -119 to -120 dB THD+N, but the 3 dB difference can easily be understood by the difference in parameters.

Strangely this doesn't happen with WDM-KS, only with JavaSound. Somehow I couldn't get WDM-KS to work at all before and used JavaSound instead (And WASAPI was only 16-bit for me). WDM-KS seems to give slightly strange results, though. I'll have to look into this further.
 
I found the reason why Phonalyser shows better THD+N than Multitone Analyzer or REW.

With my configuration THD+N is -115.9 dB when using 55 (Or less) averages:

View attachment 546802


With 56 (Or more) averages it is -129.1 dB:

View attachment 546803

Noise, Noise + Distortion and SNR are changed too by about 15 dB. The exact number of averages is not always 55 or 56, but approximately that. For example 64 averages show always better (but false) THD+N and 32 averages more realistic one. Both Multitone and REW shows about -119 to -120 dB THD+N, but the 3 dB difference can easily be understood by the difference in parameters.
It looks verz unsusual, that with only 1 average difference the noise value are so different. I suppose that the first capture was "poisoned" with some signal discontinuity and therefore noise level around fundamental is much higher. But it is vissible on maximized trace from DC to Nyquist.

For incoherent average noise floor doesn't decay with the time it will be only thiner. Therefore all noise values can't change significant.

All FFT parameters are same, only sample rate I can't see.
 
Not necessarily exactly 0 dBFS, but it would be easier to use the same unit when comparing with Multitone and REW.
Has already added enhancement issue to GitHub.

For example, on the E-MU 0404, the Toslink outputs and inputs are on channels 3 and 4 and cannot be used at all when using WASAPI, only channels 1 and 2.
Will investigate possibilities.
 
Strangely this doesn't happen with WDM-KS, only with JavaSound. Somehow I couldn't get WDM-KS to work at all before and used JavaSound instead (And WASAPI was only 16-bit for me). WDM-KS seems to give slightly strange results, though. I'll have to look into this further.
Do you use it on 32 bit Windows? Have already made fixes for WASAPI & JavaSound for 1.1.1. Let's retest it on new version, if it will be released.
 
All FFT parameters are same, only sample rate I can't see.

Nothing else was modified between the runs except 1 average less or more. The sampling rate was 44.1 kHz on both input and output. Audient iD24 feeding Topping E50 via Toslink and Cosmos ADCiso capturing the signal.
 
Do you use it on 32 bit Windows? Have already made fixes for WASAPI & JavaSound for 1.1.1. Let's retest it on new version, if it will be released.

Windows 10 64-bit. I'll test the new version when available.
 
So, I have compared my app with REW.
Same generator - from Phonalyser. Simple 1 kHz aligned to 128k FFT bin (~1000.488 Hz). Then between DAC and ADC - 1kHz notch filter (notch about 1002.4 Hz). Sample rate both 384k, all other settings identical. Frequency range 20-20k, manual fundamental 1V.
Here is REW result:
1784892451762.png

And Phonalyser result:
1784893103259.png

The are two differences groups:
  • N+D, THD+N and ENOB: there is small difference in 6dB. I have found the reason. All this values should be A-Weighted to be identical, but in my app it are not weighted. I'll fix it in the 1.1.1.
  • N is totaly different: -112.77 dBV vs -187 dBV. Honestly - I don't understand where REW gets -187 dBV. It's not even power density - it's about −154 dBV! It's totaly bullshit and can't be compared.
All other values and trace are pretty similar.


P.S. I have fixed N+D, THD+N and ENOB and it looks better now:
1784893564522.png


Thank you for pointing me!
 
Have also installed Multitone, can't collect 55 averages, cause get signal discontinuity after almost every second FFT frame. Here is only 2 averages:
1784894695194.png

SNR is here wrong, cause I have not found how to define manual fundamental, we need add 69.2dB and get SNR = 116.5 but this is dBFS. And for my Cosmos E1DA 0 dBFS = +5.07dBV. So we get 111.43 dBV, Noise 116.5 - 5.07 = 111.43 dBV, Pretty near REW and Phonalyser.
 
Last edited:
Have also installed Multitone, can't collect 55 averages, cause get signal discontinuity after almost every second FFT frame. Here is only 2 averages:
View attachment 546841
SNR is here wrong, cause I have not found how to define manual fundamental, we need add 69.2dB and get SNR = 116.5 but this is dBFS. And for my Cosmos E1DA 0 dBFS = +5.07dBV. So we get 111.43 dBV, Noise 116.5 - 5.07 = 111.43 dBV, Pretty near REW and Phonalyser.


You should be able to use Multitone with Phonalyser generator using the "External source" -selection. This is from my phone as a source, synced 128 averages with no problem:

1784905004745.png


You can notch the carrier too, if you want:

1784905166899.png
 
... and this is from Phonalyser generator, 128 averages:

1784905808759.png
 
Ok, thank you. Now I can collect data with the same parameters as REW and Phonalyser:
1784906955938.png

In my opinion all noise/THD values wrong. Only peak is correct.
THD -> -64.3dBV - 69dB(notch) = 0.000021% (should be 0.000009%)
Noise -> -118.4dBV Phonalyser (1.1.1) -112.8dBV (REW - totaly wrong -187dBv)
N+D -> -120dBV REW/Phonalyser(1.1.1) -118dBV
ENOB 20.1 REW/Phonalyser(1.1.1) 19.3
 
Ok, thank you. Now I can collect data with the same parameters as REW and Phonalyser:
View attachment 546900
In my opinion all noise/THD values wrong. Only peak is correct.
THD -> -64.3dBV - 69dB(notch) = 0.000021% (should be 0.000009%)
Noise -> -118.4dBV Phonalyser (1.1.1) -112.8dBV (REW - totaly wrong -187dBv)
N+D -> -120dBV REW/Phonalyser(1.1.1) -118dBV
ENOB 20.1 REW/Phonalyser(1.1.1) 19.3

Changing the "Vertical units" to dBV only changes the plot units, not the units on the THD panel on the right. They are still as dB.
 
Changing the "Vertical units" to dBV only changes the plot units, not the units on the THD panel on the right. They are still as dB.
Ok, this means that to all dB values should be added 5.07dB (It is difference between dBFS and dBV). Many value are then ok, ENOB still differs (actually it's not dBFS/dBV more)
It's little bit inconvenient - not all value are relative and show it as dB - is then unclear what it is.
 
Back
Top Bottom