• 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)

I see, Google says all depends on ALSA PulseAudio/PipeWire being set up correctly.

So on windoze I guess ASIO?
 
I almost forgotten, that in addition to builtin and USB cards there is a lot of other interfaces OCIe, SPDIF etc.
So I have updated device-scanner. https://edgo.org/scope/device-scanner-1.2.1.jar
@Rantapossu & @audio_tony please run it again if there any improvements in card/modes detction.
If yes - I will made bugfix release 1.2.1

It seems to identify my SMSL PO100AK DAC as "AUDIO [plughw:0,0] (Headphone Out) - ALSA" no idea why....

I think I see what it's not identifying the Asus correctly. Javasound is enumerating /proc/asound/cards

So all it sees is "STX" (in the app) but yet device scanner seems to provide a more comprehensive list.

Yesterday, with the online version of Pholyser I was able to view the input of the Asus card but in the local app I can't.

And with the web app, I couldn't generate a signal, but with the local app I can? I was mistaken in my previous post when I said I couldn't - I hadn't noticed the the generator was defaulting to 5 seconds!!!! (you probably want to make this default 30s at least).

EDIT: I just tried enumerating the audio devices in C (code attached) and I get this:

Compile with: gcc -o alsa_hw_enum alsa_hw_enum.c -lasound

Card 0: SMSL USB AUDIO (SMSL SMSL USB AUDIO at usb-0000:05:00.0-2, high speed)
[OUTPUT] Device hw:0,0 -> USB Audio (Subdevices: 1)
--------------------------------------------------
Card 1: Xonar STX (Asus Virtuoso 100 at 0xb000, irq 19)
[OUTPUT] Device hw:1,0 -> Multichannel (Subdevices: 1)
[OUTPUT] Device hw:1,1 -> Digital (Subdevices: 1)
[INPUT ] Device hw:1,0 -> Multichannel (Subdevices: 1)
[INPUT ] Device hw:1,1 -> Digital (Subdevices: 1)
--------------------------------------------------


cat /proc/asound/cards
0 [AUDIO ]: USB-Audio - SMSL USB AUDIO
SMSL SMSL USB AUDIO at usb-0000:05:00.0-2, high speed
1 [STX ]: AV200 - Xonar STX
Asus Virtuoso 100 at 0xb000, irq 19



Phonalyser device scanner
scanned : 2026-08-10 09:09:38
os : Linux 6.1.0-41-amd64 (amd64)
java : 26.0.2 - Oracle Corporation
note : managers built fresh, no caches - every figure below was probed live by this run

JavaSound mixer providers on the class path:
- com.sun.media.sound.DirectAudioDeviceProvider
- com.sun.media.sound.PortMixerProvider
- com.cleansine.sound.provider.SimpleMixerProvider

=== WASAPI ===
not available on this OS (Linux 6.1.0-41-amd64 (amd64))

=== WDM-KS ===
not available on this OS (Linux 6.1.0-41-amd64 (amd64))

=== JavaSound ===
device list: enumerated fresh
INPUT devices:
[0] STX [plughw:1,0] (Direct Audio Device: Xonar STX, Multichannel) - ALSA
32000 Hz: 16 32 bits
44100 Hz: 16 32 bits
48000 Hz: 16 32 bits
88200 Hz: 16 32 bits
96000 Hz: 16 32 bits
176400 Hz: 16 32 bits
192000 Hz: 16 32 bits
[1] STX [plughw:1,1] (Direct Audio Device: Xonar STX, Digital) - ALSA
44100 Hz: 16 32 bits
48000 Hz: 16 32 bits
88200 Hz: 16 32 bits
96000 Hz: 16 32 bits
176400 Hz: 16 32 bits
192000 Hz: 16 32 bits
OUTPUT devices:
[0] AUDIO [plughw:0,0] (Headphone Out) - ALSA
44100 Hz: 32 bits
48000 Hz: 32 bits
88200 Hz: 32 bits
96000 Hz: 32 bits
176400 Hz: 32 bits
192000 Hz: 32 bits
352800 Hz: 32 bits
384000 Hz: 32 bits
705600 Hz: 32 bits
768000 Hz: 32 bits
[1] STX [plughw:1,0] (Direct Audio Device: Xonar STX, Multichannel) - ALSA
32000 Hz: 16 32 bits
44100 Hz: 16 32 bits
48000 Hz: 16 32 bits
88200 Hz: 16 32 bits
96000 Hz: 16 32 bits
176400 Hz: 16 32 bits
192000 Hz: 16 32 bits
[2] STX [plughw:1,1] (Direct Audio Device: Xonar STX, Digital) - ALSA
32000 Hz: 16 32 bits
44100 Hz: 16 32 bits
48000 Hz: 16 32 bits
88200 Hz: 16 32 bits
96000 Hz: 16 32 bits
176400 Hz: 16 32 bits
192000 Hz: 16 32 bits
scan time: 0.1 s

=== CoreAudio ===
not available on this OS (Linux 6.1.0-41-amd64 (amd64))

alsa-mixer.png
alsa-mixer2.png
 

Attachments

Last edited:
Ok, I have updated scanner to 1.2.2: https://edgo.org/scope/device-scanner-1.2.2.jar
Please re-run. It should list something like:
INPUT:
AV200 - Xonar STX - Multichannel
AV200 - Xonar STX - Digital
OUTPUT:
SMSL USB AUDIO - Headphone Out
AV200 - Xonar STX - Multichannel
AV200 - Xonar STX - Digital

Here you are - looks like it's detecting everything correctly now. I'm curious to know; what is the 16 in the Asus output?

96000 Hz: [B]16[/B] 32 bits - I note that the SMSL only has two columns: 96000 Hz: 32 bits

I also plugged in my Altor Audio Olivine 2 ADC - and it detected that as well.
OLIVINE-2 ADC V1.23 - Line In - ALSA 96000 Hz: 24 bits

Another interesting quirk. After plugging in the Olivine ADC I thought I'd try phonolyser (local version) again.

I can see the sine on the scope, but the FFT window was displaying nothing. I turned the volume up and done in the ADC and suddenly the FFT burst into life - however it didn't look very good....

Phonalyser device scanner
scanned : 2026-08-11 08:58:58
os : Linux 6.1.0-41-amd64 (amd64)
java : 26.0.2 - Oracle Corporation
note : managers built fresh, no caches - every figure below was probed live by this run

JavaSound mixer providers on the class path:
- com.sun.media.sound.DirectAudioDeviceProvider
- com.sun.media.sound.PortMixerProvider
- com.cleansine.sound.provider.SimpleMixerProvider

=== JavaSound ===
device list: enumerated fresh
INPUT devices:
[0] AV200 - Xonar STX - Multichannel - ALSA
32000 Hz: 16 32 bits
44100 Hz: 16 32 bits
48000 Hz: 16 32 bits
88200 Hz: 16 32 bits
96000 Hz: 16 32 bits
176400 Hz: 16 32 bits
192000 Hz: 16 32 bits
[1] AV200 - Xonar STX - Digital - ALSA
44100 Hz: 16 32 bits
48000 Hz: 16 32 bits
88200 Hz: 16 32 bits
96000 Hz: 16 32 bits
176400 Hz: 16 32 bits
192000 Hz: 16 32 bits
[2] OLIVINE-2 ADC V1.23 - Line In - ALSA
96000 Hz: 24 bits
OUTPUT devices:
[0] AV200 - Xonar STX - Multichannel - ALSA
32000 Hz: 16 32 bits
44100 Hz: 16 32 bits
48000 Hz: 16 32 bits
88200 Hz: 16 32 bits
96000 Hz: 16 32 bits
176400 Hz: 16 32 bits
192000 Hz: 16 32 bits
[1] AV200 - Xonar STX - Digital - ALSA
32000 Hz: 16 32 bits
44100 Hz: 16 32 bits
48000 Hz: 16 32 bits
88200 Hz: 16 32 bits
96000 Hz: 16 32 bits
176400 Hz: 16 32 bits
192000 Hz: 16 32 bits
[2] SMSL USB AUDIO - Headphone Out - ALSA
44100 Hz: 32 bits
48000 Hz: 32 bits
88200 Hz: 32 bits
96000 Hz: 32 bits
176400 Hz: 32 bits
192000 Hz: 32 bits
352800 Hz: 32 bits
384000 Hz: 32 bits
705600 Hz: 32 bits
768000 Hz: 32 bits
scan time: 0.1 s
 
Last edited:
Here you are - looks like it's detecting everything correctly now. I'm curious to know; what is the 16 in the Asus output?

96000 Hz: [B]16[/B] 32 bits - I note that the SMSL only has two columns: 96000 Hz: 32 bits

I also plugged in my Altor Audio Olivine 2 ADC - and it detected that as well.
OLIVINE-2 ADC V1.23 - Line In - ALSA 96000 Hz: 24 bits

Another interesting quirk. After plugging in the Olivine ADC I thought I'd try phonolyser (local version) again.

I can see the sine on the scope, but the FFT window was displaying nothing. I turned the volume up and done in the ADC and suddenly the FFT burst into life - however it didn't look very good....
Nice, thank you for the test. I have also made more tests on my Linux box.
Xonar Essense STX allows up to 24 bit. But used PCM1792A DAC accepts 16-, 20-, and 24 Bit. Maybe 20 bit doesn't acceped by software (cannot be aligned to byte)
Ok, I'll finalyze bugfix release 1.2.1
 
So, bugfix release 1.2.1 is public https://github.com/dgo42/Phonalyser/releases/tag/v1.2.1
New:
- Digital loopback backend (desktop + web): playback feeds capture with nothing
but arithmetic in between, dithered at the last bit - a bench with a known
noise floor, no hardware needed.
- QA40x sharing: the analyzer is released the moment nothing measures with it,
so the vendor software or another Phonalyser can take it without restarts.
Factory calibration is read once per serial and cached; a fresh card defaults
to the protected ranges (+42 dBV in / -12 dBV out).
- One universal server jar for all platforms and architectures; downloads stay
per-platform ZIPs (natives, launcher, service scripts).
- THD/IMD table levels readable in any unit, standalone device scanner, FAQ
chapter in the help, real device names on Linux.
Fixed, among others:
- The largest FFT lengths (4M and up at low rates) never produced a spectrum -
the frame is now gathered across reads instead of demanding 87 s from a 22 s
buffer in one piece.
- WASAPI-exclusive: 24/32-bit-only devices refused, 24-in-32 containers not
offered at 24, unstable default formats.
- Wide input ranges blocked the scope's calibrate button; closing the sweep
progress window did not stop the sweep; snap-to-bin used the wrong clock with
unequal rates.
- Web app: a sample-rate change now reaches a QA40x with the generator running,
restarts really start from zero, an overrun keeps the running average, and
the browser can start the generator from a deployed build.
Note: net protocol is v2 - update server and clients together. QA40x over
WebUSB works in Chrome, Chromium and Brave; Edge and Opera are Web Audio only.
 
I just tried 1.2.1 on my Linux box. At first start of the program, I get a choice of the correct audio devices.

However - neither the scope or the FFT read anything - they just remain blank.

If I restart the app, there are no audio devices to choose from - they are all just blank and cannot be edited. Starting the oscillator results in an error messages advising mt to choose a suitable audio device.

If I exit the app, delete ~/.config/Phonalyser and restart - I an then able to select devices again, but the scope and fft still don't work.

When I look in devices.yaml - I only see the SMSL device.

But after deleting the config directory and starting again, I do see the Asus device.

EDIT: After some research with Gemini, it was indicated that Javasound has some quirks when both input and output are not the same device.

It advised me to create a new ~/.asoundrc as follows:

I did this - and then the scope started working - but the FFT still wouldn't work. I restarted the app and..... all drivers gone....

I ran device-scanner-1.2.2.jar and it was still able to detect all devices correctly.

# Define the asymmetric physical routing
pcm.asym_split {
type asym
playback.pcm "hw:1,0"
capture.pcm "hw:0,0"
}

# Wrap the split in a plug layer for sample rate conversion
pcm.javasound_bridge {
type plug
slave.pcm "asym_split"
}

# Force the system default to use our Java-friendly bridge
pcm.!default {
type copy
slave.pcm "javasound_bridge"
}

ctl.!default {
type hw
card 1
}

This is what Gemini quoted:

Your current .asoundrc is syntactically correct for standard Linux applications, but it is hitting a strict quirk in how JavaSound handles ALSA devices.
Standard Linux apps see your asym layout as one device. However, JavaSound interacts with ALSA by querying the system mixers via getMixerInfo(). It loops through hw:0 (your Xonar STX) and hw:1 (your SMSL DAC) individually, but it completely ignores pcm.!default if it is configured as an asymmetric compound device without an explicit configuration name that maps to Java's expected hardware structure.
To force JavaSound to see a single, unified device containing both playback and capture capabilities, update your ~/.asoundrc to include a dedicated Java-compatible plug layer like this: (see ~./asoundrc above)

<snip>
output:
channels: LINKED
ranges:
- { label: "default", fsVrms: { left: 1.0, right: 1.0 } }
activeRange: "default"
- name: SMSL USB AUDIO - Headphone Out
match: [ "SMSL USB AUDIO - Headphone Out" ]
output:
channels: LINKED
ranges:
- { label: "default", fsVrms: { left: 0.7071067811865475, right: 0.7071067811865475 } }
activeRange: "default"
bindings:
"SMSL USB AUDIO - Headphone Out": "SMSL USB AUDIO - Headphone Out"

But...

After restarting...

<snip>
output:
channels: LINKED
ranges:
- { label: "default", fsVrms: { left: 1.0, right: 1.0 } }
activeRange: "default"
- name: SMSL USB AUDIO - Headphone Out
match: [ "SMSL USB AUDIO - Headphone Out" ]
output:
channels: LINKED
ranges:
- { label: "default", fsVrms: { left: 0.7071067811865475, right: 0.7071067811865475 } }
activeRange: "default"
bindings:
"SMSL USB AUDIO - Headphone Out": "SMSL USB AUDIO - Headphone Out"

preferences.yaml:

<snip>
perBackend:
WASAPI:
inputDeviceName: null
outputDeviceName: null
inputSampleRate: 384000
inputBitDepth: 24
outputSampleRate: 384000
outputBitDepth: 24
JAVASOUND:
inputDeviceName: AV200 - Xonar STX - Multichannel
outputDeviceName: SMSL USB AUDIO - Headphone Out
inputSampleRate: 96000
inputBitDepth: 32
outputSampleRate: 96000
outputBitDepth: 32

preferences.yaml with no drivers: (all set to NULL - and unable to add or edit))

<snip>
perBackend:
JAVASOUND:
inputDeviceName: null
outputDeviceName: null
inputSampleRate: 32000
inputBitDepth: 16
outputSampleRate: 384000
outputBitDepth: 32
WASAPI:
inputDeviceName: null
outputDeviceName: null
inputSampleRate: 384000
inputBitDepth: 24
outputSampleRate: 384000
outputBitDepth: 24

The logfile reports nothing of relevance.

And finally:

java --version
java 26.0.2 2026-07-21
Java(TM) SE Runtime Environment (build 26.0.2+10-55)
Java HotSpot(TM) 64-Bit Server VM (build 26.0.2+10-55, mixed mode, sharing)
 
However - neither the scope or the FFT read anything - they just remain blank.
Did you started generator? Has scope at least shows capture per second in the top right corner? Has FFT start to show data capturing - top right corner percentage?
If I restart the app, there are no audio devices to choose from - they are all just blank and cannot be edited. Starting the oscillator results in an error messages advising mt to choose a suitable audio device.

If I exit the app, delete ~/.config/Phonalyser and restart - I an then able to select devices again, but the scope and fft still don't work.
Hmm, strengh
When I look in devices.yaml - I only see the SMSL device.
devices.yaml contains only device configuration like available ranges and calibration values independent of which backend is used. Record for devices apears here obly after you create empty config for new device:
1786915480685.png

1786915504292.png

I don't see differences in devices.yaml. And you show only output device
What is really strength, that scope has worked and FFT not. They uses same ring buffer. And if one works - should also work another module.
P.S. I have tryed it on my Linux VM - you may need some time after start to enmerate ALSA devices. Before that all combos will be empty.
On Linux it is something longer as on Windows.
 
I don't see differences in devices.yaml. And you show only output device
What is really strength, that scope has worked and FFT not. They uses same ring buffer. And if one works - should also work another module.
That's because during testing the input device disappears...

I definitely started the generator - I set the duration to 600s so plenty of time for things to "warm up" (as so to speak).

When the scope does work, enable the FFT and it begins counting the averages etc. but simply never displays anything.

Here's a video to demonstrate the 'scope / fft issue.

 
Thank you for video. I must think...
I definitely started the generator - I set the duration to 600s so plenty of time for things to "warm up" (as so to speak).
Duration doesn't mater. It is used only to save generated signal to audio file.
When the scope does work, enable the FFT and it begins counting the averages etc. but simply never displays anything.
That is really strength. In FFT you use left channel. It look like there is absolutely no signal - only zeros. Only in this case there will be no FFT trace because "signal" will be much below -300dB. But we see parallel working scope and in scope measurement table value changed, this means that scope gets real signal.
In addition devices lists in preference dialog are empty.
P.S. Can you please switch FFT to the right channel. I have hope that this is at least a reason why in FFT is nothing to see ¯\_(ツ)_/¯. For other problem, that device slists are empty I must dive deeper in code.
P.P.S. No, on the scope I see both channel draws identical sine. It should no matter which channel to use in FFT. That is definitive at least to issues - device list & FFT got no signal
 
Last edited:
As of the device enumeration in linux java - the stock JVM alsa javasound connector enumerates only hw (card) devices. Also it prepends the plug plugin (hard-coded in the connector source code). PCM devices (those created by alsa configuration) are not enumerated at all. That's the reason for creating https://github.com/pavhofman/csjsound-alsapcm/ , initially for REW to solve the same issue.

I do not think we hit any issue in javasound with linked in/out devices in REW (a similar app). The access to each direction should be independent. If capture and playback run in separate threads (which they should), they can each access/work with different devices (i.e. those that run asynchronously). Of course reading/writing to different devices in the same thread would cause buffer issues and lock ups, unless specifically taking care of the devices asynchronous timing.
 
So, bugfix release 1.2.1 is public https://github.com/dgo42/Phonalyser/releases/tag/v1.2.1
New:
- Digital loopback backend (desktop + web): playback feeds capture with nothing
but arithmetic in between, dithered at the last bit - a bench with a known
noise floor, no hardware needed.
- QA40x sharing: the analyzer is released the moment nothing measures with it,
so the vendor software or another Phonalyser can take it without restarts.
Factory calibration is read once per serial and cached; a fresh card defaults
to the protected ranges (+42 dBV in / -12 dBV out).
- One universal server jar for all platforms and architectures; downloads stay
per-platform ZIPs (natives, launcher, service scripts).
- THD/IMD table levels readable in any unit, standalone device scanner, FAQ
chapter in the help, real device names on Linux.
Fixed, among others:
- The largest FFT lengths (4M and up at low rates) never produced a spectrum -
the frame is now gathered across reads instead of demanding 87 s from a 22 s
buffer in one piece.
- WASAPI-exclusive: 24/32-bit-only devices refused, 24-in-32 containers not
offered at 24, unstable default formats.
- Wide input ranges blocked the scope's calibrate button; closing the sweep
progress window did not stop the sweep; snap-to-bin used the wrong clock with
unequal rates.
- Web app: a sample-rate change now reaches a QA40x with the generator running,
restarts really start from zero, an overrun keeps the running average, and
the browser can start the generator from a deployed build.
Note: net protocol is v2 - update server and clients together. QA40x over
WebUSB works in Chrome, Chromium and Brave; Edge and Opera are Web Audio only.

Thanks!

There is now 24-bit option:

1787026855363.png


But when I press the Play-button, I get this:

1787026925344.png


Editing manually the preferences.yaml -file to...

outputSampleRate: 44100
outputBitDepth: 32

... makes everything to work again.
 
Last edited:
THD/IMD table level units are now switchable, but as far as I see, this only affects the harmonics.

Other values are still a mix of dBV and percentages:
1787029033878.png


Could you consider using these 4 options that changes the output of the whole panel?

dBV
dBFS
dB
%
 
@audio_tony I have made some changes. Please try run preliminar 1.2.2 version.
Now app writes in log sound cards enumeration process like this:
Device format probe started: AudioPCI [plughw:0,0] (input)
Device format probe finished: AudioPCI [plughw:0,0] (input) - 14 format(s) in 2171 ms
Device format probe started: CB5 [plughw:1,1] (input)
Device format probe finished: CB5 [plughw:1,1] (input) - 8 format(s) in 54 ms
Device format probe started: AudioPCI [plughw:0,0] (output)
Device format probe finished: AudioPCI [plughw:0,0] (output) - 8 format(s) in 74 ms
Device format probe started: AudioPCI [plughw:0,1] (output)
Device format probe finished: AudioPCI [plughw:0,1] (output) - 8 format(s) in 1017 ms
Device format probe started: CB5 [plughw:1,1] (output)
Device format probe finished: CB5 [plughw:1,1] (output) - 18 format(s) in 40 ms
Please take a look
 
As of the device enumeration in linux java - the stock JVM alsa javasound connector enumerates only hw (card) devices. Also it prepends the plug plugin (hard-coded in the connector source code). PCM devices (those created by alsa configuration) are not enumerated at all. That's the reason for creating https://github.com/pavhofman/csjsound-alsapcm/ , initially for REW to solve the same issue.

I do not think we hit any issue in javasound with linked in/out devices in REW (a similar app). The access to each direction should be independent. If capture and playback run in separate threads (which they should), they can each access/work with different devices (i.e. those that run asynchronously). Of course reading/writing to different devices in the same thread would cause buffer issues and lock ups, unless specifically taking care of the devices asynchronous timing.
Make sence, will try it soon too
 
Editing manually the preferences.yaml -file to...

outputSampleRate: 44100
outputBitDepth: 32

... makes everything to work again.
Hmmm, have you tried other backend: WDM-KS or JavaSound?
 
Hmmm, have you tried other backend: WDM-KS or JavaSound?

WDM-KS works with 24-bit.

JavaSound shows only 32-bit selection and it works. The difference with WASAPI is that with JavaSound you can select it directly from the Phonalyser settings and with WASAPI you have to manually edit the preferences.yaml file, because there is no 32-bit option to select in the WASAPI settings. You will have to save 16-bit depth and edit the file.
 
Back
Top Bottom