ja11-config-tui⚓︎
- Homepage: https://github.com/Freetz-NG/freetz-ng
- Repository (source): master/make/pkgs/ja11-config-tui/
- Library: master/make/libs/hidapi/
- Hardware: FiiO JA11 (JadeAudio JA11) / KT Micro KT02H20
- Protocol reference: Audiocular-Aura
What is ja11-config-tui⚓︎
ja11-config-tui is a Text-based User Interface (TUI) program that configures the
FiiO JA11 USB DAC/Amp and other devices based on the KT Micro KT02H20 DSP chip
(JKALLY JM12, etc.).
The tool communicates directly with the hardware via HID — it sends
binary commands to the chip's Digital Signal Processor (DSP) to set the 5-band
Parametric Equalizer (PEQ), DAC digital filters, and global preamp gain.
Because commands target the hardware directly, settings can be made persistent:
with the Save to Flash feature, your custom sound signature remains even when
you unplug the DAC and connect it to a phone, tablet, or game console.
Features⚓︎
- Full TUI control — Interactive ncurses interface with real-time feedback.
- 5-band Parametric EQ — Independent control of Frequency, Gain, Q-Factor and
Filter Type (Peaking / Low-Shelf / High-Shelf) for each band. - Global Preamp (Gain) — Overall volume trim to prevent digital clipping when
boosting EQ bands. - DAC Digital Filter selection — Five filters of the KT02H20 DAC: FAST-LL,
FAST-PC, Slow-LL, Slow-PC, NON-OS. - Hardware-level changes — Settings are written directly to the DSP over HID;
no audio server (ALSA/PulseAudio) configuration needed. - Persistent flash memory — Save your configuration to the device's internal
flash so it survives power cycles and host changes. - Preset management — Save, load, and delete EQ profiles stored locally on
the host (/tmp/ja11-presets.conf). - i18n — English (default) and Italian (
--italian/-it). - Lightweight — Written in C with only two external dependencies:
hidapi(libusb backend, likehidws) andncurses.
How it works⚓︎
Communication protocol⚓︎
The KT02H20 chip uses a HID output report with Report ID 0x02. All
commands (including read requests) are sent via the interrupt OUT endpoint
(hid_write, equivalent to Audiocular-Aura's device.sendReport(2, …)), and
the responses come back as input reports on the interrupt IN endpoint.
Commands are wrapped in fixed-length packets with the following structure:
Set (write) packet:
Read (response) packet:
Note: hidapi's libusb backend (and the
hidwsWebSocket bridge) returns
the report ID byte (0x02) as the first byte of numbered input
reports, i.e. the buffer is0x02 0xbb 0x0b …. The TUI strips it
(find_packet_start()) before parsing, exactly like the web apps do.
Key commands:
| Cmd | Name | Purpose |
|---|---|---|
| 17 | DAC_FILTER | Set DAC digital filter (1-5) |
| 21 | FILTER_PARAMS | Write a single PEQ band (freq, gain, Q, type) |
| 23 | GLOBAL_GAIN | Read/write global preamp gain |
| 24 | APPLY | Commit current settings to RAM |
| 25 | SAVE_FLASH | Persist settings to flash memory |
Data encoding:
- Gain: signed Q12 fixed-point (value × 10), 2-byte big-endian; negative
values are 16-bit two's complement (65536 + value).
- Frequency: Hz as unsigned 2-byte big-endian.
- Q factor: Q2 fixed-point (value × 100), 2-byte big-endian.
- Global gain: signed value × 2560, 2-byte little-endian; negative values
are 16-bit two's complement.
Pipeline⚓︎
User edits params in TUI
↓
(key 'a') → sync_all_bands() + apply_changes() → DSP RAM
↓
(key 's' then 'S') → sync_all_bands() + save_to_flash() → DSP flash
↓
(key 'r'/'R') → read_device_config() → reload from DSP → UI
The Apply step (a) is instantaneous — you hear the change immediately. The
Save step (s → S) writes all current bands plus the global gain and DAC
filter to non-volatile flash, making the setting permanent.
Current packaged versions⚓︎
ja11-config-tui:1.0hidapi:0.15.0(shared library dependency)
Source-based behavior map⚓︎
Main files that define the current behaviour:
make/pkgs/ja11-config-tui/src/ja11-config-tui.c— TUI logic, HID I/O,
preset management, main loop.make/pkgs/ja11-config-tui/src/ja11-config-tui.h— Protocol constants,
data structures, limits, i18n codes.make/pkgs/ja11-config-tui/ja11-config-tui.mk— Build recipe
(PKG_LOCALSOURCE_PACKAGE, links libhidapi-libusb + ncurses + m).make/pkgs/ja11-config-tui/Config.in— Menuconfig options
(selects FREETZ_LIB_hidapi, FREETZ_LIB_libncurses).make/pkgs/ja11-config-tui/external.files/in— Externalisation manifest.make/libs/hidapi/hidapi.mk— CMake-based HIDAPI library build.make/libs/hidapi/patches/— Patches to make udev optional for freetz.make/libs/hidapi/Config.in— Library config symbol FREETZ_LIB_hidapi.
Usage⚓︎
With the FiiO JA11 connected via USB, run:
Use --italian (or -it) for Italian UI:
Device selection⚓︎
On startup the tool enumerates all HID devices (via the hidapi libusb
backend, the same approach used by hidws) and shows a picker:
┌────────────────────────────── Select HID device ─────────────────────────────┐
│ VID:PID Product │
│ * 2972:0102 JadeAudio JA11 ← known KT02H20 device (auto ✓) │
│ 31b2:0111 JM12 │
│ 046d:c52b USB Receiver │
│ Up/Down: move Enter: connect q: quit │
└──────────────────────────────────────────────────────────────────────────────┘
- Devices whose VID/PID or product string matches a known KT02H20 device
(2972:0102,31b2:0111, or names containingJA11/ja11/KT02H20/JM12)
are marked with*and pre-selected. - Enter connects to the highlighted device; q quits.
- In the main screen, press
cto reopen the picker (reconnect or switch
to another device).
If no HID device is found at all, the tool shows the error/hint and stays on
the (disconnected) main screen.
If a device is not accessible, run as root (normal on the router). On desktop
hosts see the udev rule below for non-root access.
Interface layout⚓︎
┌─────────────────────────────────────────────────────────────────────────────┐
│ CONNECTED: FiiO JA11 Preamp: -3.5 dB DAC: FAST-LL All synced with device│ ← status bar
├──────┬──────────────┬──────────────┬──────────────┬──────────┬──────────────┤
│ Band │ Freq (Hz) │ Gain (dB) │ Q │ Type │ Status │
├──────┼──────────────┼──────────────┼──────────────┼──────────┼──────────────┤
│ >1 │ 63 │ -2.0 │ 0.70 │ PK │ ON │ ← selected band
│ 2 │ 250 │ +3.5 │ 1.20 │ PK │ ON │
│ 3 │ 1000 │ 0.0 │ 0.70 │ LSQ │ OFF │
│ 4 │ 4000 │ +1.8 │ 1.50 │ HSQ │ ON │
│ 5 │ 14000 │ 0.0 │ 0.70 │ PK │ ON │
├──────┴──────────────┴──────────────┴──────────────┴──────────┴──────────────┤
│ ░░ │ ← gain bar chart
│ ░░░░ │
│ ░░░░░░░░ │
│ ─══════════════════════════════════════════════════════════════════─ │
│ ░░░░ ░░ │
│ ░░░░ ░░ │
│ ─══════════════════════════════════════════════════════════════════─ │
├─────────────────────────────────────────────────────────────────────────────┤
│ English FiiO JA11 / KT02H20 │ ← help panel
│ === NAVIGATION === │
│ Arrows Move between bands/params │
│ +/- Change value (coarse step) │
│ </> Change value (fine step) │
│ Space Toggle band on/off │
│ t Cycle filter type (PK/LSQ/HSQ) │
│ Tab/Shift-Tab Move fwd/back across all cells │
│ === DEVICE ACTIONS === │
│ a Apply changes to RAM │
│ s (then S) Save to flash (permanent) │
│ r / R Reload config from device │
│ g / G Set global preamp gain │
│ f / F Cycle DAC digital filter │
│ === PRESETS === │
│ p Save current preset │
│ P Load preset │
│ K Delete current preset │
│ === OTHER === │
│ d Reset to flat (0 dB, Q=0.7) │
│ D Reset to defaults (optimal freqs) │
│ q / Q Quit │
├─────────────────────────────────────────────────────────────────────────────┤
│ OK: Saved to flash. │ ← status message
└─────────────────────────────────────────────────────────────────────────────┘
The help panel at the bottom is drawn only if the terminal is tall enough;
on small terminals it is replaced by a Press ? or h for full help hint, and
the full, scrollable help is available anytime with ? / h / H.
Controls reference⚓︎
| Key(s) | Action | Description |
|---|---|---|
| ↑/↓ | Select band | Move cursor between the 5 PEQ bands. |
| ←/→ | Select parameter | Move cursor between Freq, Gain, Q, Type columns. |
Tab/Shift+Tab |
Cycle cells (fwd/back) | Move forward/backward across all cells (band × Freq/Gain/Q/Type/Status). |
+/- |
Coarse adjust | Change parameter by a large step (10 Hz, 1 dB, 0.1 Q); on Type it cycles the filter, on Status it toggles the band. |
</> |
Fine adjust | Change parameter by a small step (1 Hz, 0.5 dB, 0.01 Q). |
Space |
Toggle band | Enable/disable the selected band (bypass filter). |
t/T |
Cycle filter type | PK → LSQ → HSQ → PK … |
a/A |
Apply to RAM | Write all bands + gain + filter to device RAM (hear changes instantly). |
s then S |
Save to flash | Apply + persist to flash. Confirms with a second keypress. |
r/R |
Read from device | Discard local changes and re-read full config from DSP. |
g/G |
Set global gain | Opens an inline prompt to type a preamp value (-12…+12 dB); applies it to the device immediately. |
f/F |
Cycle DAC filter | FAST-LL → FAST-PC → Slow-LL → Slow-PC → NON-OS → … |
p |
Save preset | Opens a prompt to name the current config and save it locally. |
P (Shift+p) |
Load preset | Opens a prompt to select a previously saved preset by number. |
K (Shift+k) |
Delete preset | Removes the active preset after confirmation. |
d |
Reset to flat | All bands: 0 dB gain, 0.7 Q, PK type, enabled. |
D (Shift+d) |
Reset to defaults | All bands set to a useful frequency distribution (32/64/125/250/500 Hz). |
?/h/H |
Full help | Opens a full-screen, scrollable help viewer (useful on small terminals). |
q/Q |
Quit | Exits the program; prompts if there are unsaved changes. |
Important: q will refuse to exit while the "** MODIFICATIONS NOT APPLIED **"
warning is shown. Apply or revert first.
Understanding the parameters⚓︎
Parametric EQ (PEQ)⚓︎
A Parametric Equalizer is the most flexible type of EQ. Unlike a Graphic EQ
(which offers fixed frequency sliders), a PEQ gives you independent control of
three parameters per band:
Frequency (Hz)⚓︎
The centre frequency of the filter — the point in the audio spectrum that will
be boosted or cut.
| Range | Perceived region | Common sources |
|---|---|---|
| 20 – 160 Hz | Sub-bass / Bass | Kick drum, bass guitar, low synth pads |
| 160 – 500 Hz | Low mids | Low vocals, cello, warmth / mud |
| 500 – 2000 Hz | Midrange | Vocals, snare, guitar body |
| 2000 – 6000 Hz | Upper mids | Presence, attack, nasality |
| 6000 – 20000 Hz | Treble / Air | Cymbals, hi-hat, sibilance, sparkle |
Gain (dB)⚓︎
The amount of boost or cut applied at the centre frequency.
- Positive values (e.g. +3.0 dB) = make that range louder.
- Negative values (e.g. -4.5 dB) = make that range quieter.
- A +3 dB change is generally perceived as a doubling of loudness for that band.
Warning: Excessive boost without a corresponding negative preamp will cause
digital clipping (harsh distortion). See Global Preamp.
Q Factor (Quality Factor)⚓︎
The width of the filter — arguably the most powerful and least understood PEQ
parameter.
- High Q (≈ 3.0–10.0): narrow, "surgical" curve. Targets a very specific
frequency without affecting neighbours. Use for removing a single resonant
peak or ringing artefact. - Low Q (≈ 0.5–1.4): wide, "musical" curve. Affects a broad range around
the centre frequency. Use for general tonal shaping — warming the bass,
brightening the treble.
When Q is very low (< 0.7) the filter starts to affect a very wide range,
including frequencies far from the centre. This can be desirable for shelving
behaviour (e.g. a low-Q peaking filter at 80 Hz acts almost like a bass shelf).
Filter types⚓︎
| Type | Abbreviation | Description | Typical use case |
|---|---|---|---|
| Peaking | PK | Standard bell-shaped curve that boosts or cuts a range centred on the chosen frequency. | General EQ, most corrections. |
| Low-Shelf | LSQ | Affects all frequencies below the centre frequency. Think of a classic "Bass" tone knob. | Add or remove overall low-end weight. |
| High-Shelf | HSQ | Affects all frequencies above the centre frequency. Think of a classic "Treble" tone knob. | Add air/sparkle or tame harsh highs. |
Shelving filters in the KT02H20 are implemented with a fixed slope and are
most effective when the centre frequency is placed near the edge of the region
you want to affect (e.g., an LSQ at 200 Hz for bass, an HSQ at 3000 Hz for
treble).
Global Preamp (gain)⚓︎
The Global Preamp is a single gain value applied to the entire signal before
the PEQ stage. Its main purpose is headroom management:
- Boosting EQ bands increases the overall signal level. If the total exceeds
0 dBFS, digital clipping (harsh, crackling distortion) occurs. - The preamp should be set to a negative value equal to (or greater than) the
largest positive boost across all bands.
Rule of thumb: if your highest band boost is +5.5 dB, set Global Preamp to
-5.0 dB or lower. A safe starting point is to match it to the maximum boost.
The preamp range is -12.0 dB to +12.0 dB (positive values are rarely useful
and will likely cause clipping; they are included for completeness).
DAC Digital Filters⚓︎
The KT02H20 DAC includes a digital reconstruction filter that processes the
audio stream after D/A conversion. This filter removes ultrasonic imaging
artefacts and can subtly colour the sound. Five filter profiles are available:
| # | Name | Short name | Characteristics |
|---|---|---|---|
| 1 | Fast roll-off, Linear Phase (low latency) | FAST-LL | Steep cut above 22 kHz, no phase distortion, the default. |
| 2 | Fast roll-off, Phase Compensation | FAST-PC | Steep cut, slight phase shift, warmer character. |
| 3 | Slow roll-off, Linear Phase (low latency) | Slow-LL | Gentle roll-off, clean phase response. |
| 4 | Slow roll-off, Phase Compensation | Slow-PC | Gentle roll-off, coloured phase, "analogue" feel. |
| 5 | Non-Oversampling | NON-OS | No digital filter — passes ultrasonic noise but sounds very "raw". |
The DAC filter is independent of the PEQ; it affects the final analogue output
stage. Cycle through them with f/F while listening — the difference is
subtle but noticeable on good headphones.
Presets⚓︎
Presets are stored locally on the host machine in /tmp/ja11-presets.conf
(format: plain text, one preset per block). They are not stored on the
device itself. Use presets to:
- quickly switch between different listening profiles (night mode, loudness,
neutral), - experiment without losing a known-good configuration,
- share configurations with other users (the file is human-readable).
To use a preset after loading it, you must still press a (Apply) to send
it to the device, or s (Save) to make it persistent.
Device support⚓︎
Known compatible devices⚓︎
| Vendor | VID | PID | Product | Chip |
|---|---|---|---|---|
| FiiO | 0x2972 |
0x0102 |
JadeAudio JA11 | KT02H20 |
| JKALLY | 0x31b2 |
0x0111 |
JM12 | KT02H20 |
The picker lists every HID device found on the system. Devices whose VID/PID
or product string matches a known KT02H20 device (2972:0102, 31b2:0111, or
names containing JA11/ja11/KT02H20/JM12) are marked * and pre-selected,
so the correct device is normally highlighted automatically.
udev rule⚓︎
To allow non-root users to access the device, install this udev rule at
/etc/udev/rules.d/99-fiio-ja11.rules:
Reload udev and re-plug the device:
Add your user to the plugdev group if not already:
Without the rule, run the tool as root (sudo ja11-config-tui).
The tool uses the hidapi libusb backend (not hidraw), so on the router
(where it runs as root) no udev rule is needed. The rule above only matters
for non-root desktop use.
Debugging⚓︎
Device not found⚓︎
- The picker only lists devices found by
hid_enumerate(). If the list is
empty, runlsusb— the JA11 should appear as2972:0102(FiiO) or
31b2:0111(JKALLY). - The libusb backend does not need
/dev/hidraw*or the kernel HID/INPUT
subsystem (important on GRX5 routers, wherehid.kocannot load). - Check permissions: running as root (normal on the router) is sufficient.
- Run with
sudoas a quick test on desktop hosts.
Communication errors⚓︎
- Ensure the device is not claimed by another program (e.g. close
hidws
or the browser's WebHID session first). - The libusb backend claims the USB interface directly via usbfs; on hosts
where the kernelusbhiddriver grabs the device, hidapi detaches it
automatically on open.
Presets not loading⚓︎
Presets are stored in /tmp/ja11-presets.conf, which is volatile and lost
on reboot. This is intentional — presets are meant as quick-load snapshots
during a session, not as long-term storage. Save your configuration to flash
(s then S) for permanent storage on the device.
Known issues⚓︎
- Single-device: The tool connects to the device selected in the picker.
Connecting multiple KT02H20 devices simultaneously is not supported. - HIDAPI library name: The package links the libusb backend
(libhidapi-libusb.so.0, likehidws), not hidraw. - Volatile presets: Preset files live in
/tmpand are cleared on reboot.
See also⚓︎
- Audiocular-Aura — Web-based
configuration tool for the same chip family. - hidapi — Library used for raw HID I/O.
- FiiO — Official product page for JA11.