ARSHIYASHAFIZADE/nux-lite-ctl
GitHub: ARSHIYASHAFIZADE/nux-lite-ctl
一款通过 USB-MIDI SysEx 在原生 Linux 上控制 NUX Mighty Lite BT MkII 吉他音箱的命令行工具,无需蓝牙或厂商移动应用即可完成预设管理和调音。
Stars: 0 | Forks: 0
# nux-lite-ctl
通过 **USB-MIDI SysEx** 对 **NUX Mighty Lite BT MkII** (`NGA-3BT`) 吉他音箱进行原生 Linux 控制 —— 无需 Wine、无需 Bluetooth、无需厂商 App。
官方的 Mighty App 仅限移动端且使用 BLE 通信。该音箱还有一个 USB 端口,会显示为类兼容的 USB-MIDI 设备(`1fc9:8260`, NXP),因此 App 所做的所有操作都可以通过 ALSA 的 `amidi` 在 shell 中完成。本仓库正是对这一路径进行逆向工程并在真实硬件上验证后的成果。
## 设置
需要 Python 3 和 `amidi`(在 Arch/Debian 上的包名为 `alsa-utils`)。无需进行 pip 安装。
```
$ aplay -l # nothing needed from PipeWire/JACK — raw ALSA MIDI
$ python nuxctl.py ports
NUX amp on hw:2,0,0
```
## 命令
| 命令 | 功能 |
|---|---|
| `ports` | 查找音箱的 raw-MIDI 端口 |
| `dump [slot]` | 解码并打印预设(全部 7 个槽位,或指定的某一个) |
| `backup` | 将全部 7 个预设导出到 `presets-backup.json` |
| `select <1-7>` | 切换激活的预设槽位 |
| `apply ` | 将音色规格推送到**实时缓冲区**(仅用于试听) |
| `commit <1-7>` | 将实时缓冲区写入 flash —— 永久生效,无法撤销 |
| `tuner [seconds]` | 运行音箱的调音器并在终端输出读数 |
`apply` / `commit` 刻意分为两步:音色在被永久保存之前必须先进行试听,因为该音箱**没有针对单个槽位的恢复出厂设置**。(正是出于这个原因,`presets-factory-20260729.json` 提供了出厂预设的转储文件 —— 这是 NUX 没有提供给您的还原点。)
```
$ python nuxctl.py apply songs/deftones-change.json verse_dark
Applied 'verse_dark' from Deftones - Change (In the House of Flies)
-> LIVE buffer only. Nothing written to flash.
-> Switch slots and back to discard it.
```
## 歌曲音色文件
`songs/` 目录下保存了带有注释的音色配方(Deftones ×4, Nirvana)。它们不仅仅是参数转储 —— 每种音色都记录了*为什么*每个设置要这样设定(不同年代使用的音箱模型选择、合唱效果是为了保持原声还是为了营造氛围、曲目间的调音说明,使得歌曲之间无需重新调音):
```
"verse_dark": {
"_comment": "Treble at 40 is the point - the darkest clean in any of the song files. ...",
"amp": 2,
"amp_params": [32, 60, 52, 46, 40],
"_amp_params_are": "Deluxe Rvb: Gain, Master, Bass, Middle, Treble",
...
}
```
## 协议说明
源自 [tuntorius/mightier_amp](https://github.com/tuntorius/mightier_amp)
(一款优秀的 Mighty App 开源替代品)并在硬件上进行了验证。消息采用标准的 MIDI SysEx:
| 常量 | 值 | 含义 |
|---|---|---|
| header | `F0 43 58` | SysEx 起始位 + `C` `X`(Cherub/NUX 厂商字节) |
| direction | `00` / `01` / `02` | GET / SET / REQ |
| `MSG_PRESET` | `0x0B` | 读取/写入预设槽位 |
| `MSG_CURPRESET` | `0x0C` | 当前槽位操作 |
| `MSG_SPEC_CMD` | `0x75` | 特殊命令(例如 `48` = 保存实时缓冲区) |
| `MSG_TUNER` | `0x6F` | 开启/关闭调音器数据流 |
以下是一些来之不易的避坑指南,以免您重蹈我浪费数小时的覆辙:
1. **USB 不是 BLE。** 移动端 App 会将每条消息封装在 BLE-MIDI 数据包帧中 —— `F0` 之前是 `80 80`,`F7` 之前是 `80`。在通过 USB-MIDI 传输时,这些字节*不属于消息的一部分*;ALSA 会自动处理封包。如果发送了这些字节,音箱会默默忽略您。只需发送纯粹的 `F0 .. F7` 即可。
2. **虚假的保存。** 保存命令位于 `0x75` (`MSG_SPEC_CMD`),而不是 `0x15` (`kSYX_CURSTATE`)。音箱会直接忽略 `0x15` 且不报错,因此保存操作看似成功,但实际上什么也没有写入。
3. **实时缓冲区 vs flash。** 编辑操作实际上是通过 CC(控制变更)发送到易失性的实时缓冲区中;只有在发出明确的保存命令时才会触及 flash。这正是实现“试听后提交”工作流的基础(也是其安全性的保障)。
4. **调音器模式会对非标准调音撒谎。** `guitarStandard` 会将读数强制吸附到 E 标准音,并且会错误显示 Drop C# 的最低音弦 —— 如果您不使用标准调音,全音阶(chromatic)是唯一可信的模式。`tuner` 命令默认以 Drop C# 为目标;如需修改,请编辑 `DROP_CSHARP` 以符合您的调音。
## compare-tone.py
将“听起来不一样”转化为一种测量手段,而不是争吵:录制音箱(或接收两个 WAV 文件),对比其倍频程频段的能量平衡(已针对整体电平进行归一化处理),并与参考录音进行比对。
```
python compare-tone.py record [seconds] # capture from the amp, then compare
python compare-tone.py compare A.wav B.wav # compare two existing files
```
## 许可证
MIT。协议知识基于
[tuntorius/mightier_amp](https://github.com/tuntorius/mightier_amp) —— 如果您
想在移动设备上全面控制 Mighty 系列音箱,请使用该项目。
标签:ALSA, MIDI, Python, 云资产清单, 无后门, 硬件控制, 逆向工具, 逆向工程