展示HN:在macOS上使用Behringer FCB1010 MIDI脚踏板的宏功能
摘要
fcbnerd是一个命令行工具,允许macOS用户将shell命令绑定到来自脚踏控制器(如Behringer FCB1010)的MIDI消息,从而实现自定义自动化和快捷方式。
查看缓存全文
缓存时间: 2026/09/14 23:49
JamesRyanATX/fcbnerd
来源:https://github.com/JamesRyanATX/fcbnerd
fcbnerd
漫画:一位开发者靠在宽屏显示器前喝着咖啡,踩着MIDI脚踏板上的脚踏开关,旁边一只狗正在睡觉。
使用MIDI脚踏控制器作为Mac的额外键盘。fcbnerd连接你的MIDI源,当脚踏开关或踏板发送你已绑定的消息时执行shell命令,或为每条消息输出一行JSON对象,以便其他程序判断踩踏动作的含义。
``console
$ fcbnerd -q –bind ‘1:20:127=open ~/Downloads’ –bind ‘pc:1:0=say hello’
或输出所有信息供其他程序处理:
``console
$ fcbnerd
{"type":"connected","source":"UM-ONE","time":"2026-09-14T20:01:00.120Z"}
{"type":"pc","channel":1,"program":0,"source":"UM-ONE","time":"2026-09-14T20:01:02.345Z"}
{"type":"cc","channel":1,"controller":27,"value":84,"source":"UM-ONE","time":"2026-09-14T20:01:03.910Z"}
专为Behringer FCB1010设计,但代码中没有任何FCB1010专属内容:任何CoreMIDI源均可工作。
为何采用命令行工具而非应用程序
任何需要在Mac上执行操作(如按键或运行脚本)的功能,都需要沙盒应用无法获取的权限,而且每个用户想要的操作集合也不同。fcbnerd仅读取MIDI数据,无需任何权限。操作交由你的shell处理,或由已有权限的工具处理,例如Hammerspoon (https://www.hammerspoon.org) 或Keyboard Maestro。
安装
``sh
brew trust –tap jamesryanatx/tap # Homebrew 7+ 在你信任第三方tap前不会加载它们
brew install JamesRyanATX/tap/fcbnerd
或从源码安装(需Xcode或Swift工具链,macOS 13+):
``sh
swift build -c release
cp .build/release/fcbnerd /usr/local/bin/
用法
``
fcbnerd [listen] [–source NAME] [–format json|text] [–bind BINDING]… [–quiet] [–shell PATH]
fcbnerd list [–format json|text]
fcbnerd simulate
- **`listen`**(默认)连接所有MIDI源,或仅连接名称包含`--source`的源,并持续输出事件直至中断。支持热插拔:演奏中拔掉接口再插回,流会继续输出`disconnected`/`connected`行。
- **`list`** 打印当前可用的源。
- **`simulate`** 发布名为`fcbnerd simulator`的虚拟MIDI源,循环播放合成踩踏、踏板扫描和sysex消息。在一个终端运行它,在另一个终端运行`fcbnerd`即可在未连接踏板时构建消费者。
- **`--format text`** 打印对齐的列便于查看,包括每条可绑定消息的`bind=`模式。脚本应使用默认JSON格式;文本布局可能变化。
- **`--bind`** 当消息匹配时运行命令;详见下文。
- **`--quiet`** 停止打印事件,仅保留绑定的命令。
- **`--shell PATH`** 选择运行绑定命令的shell(默认`/bin/sh`)。
状态信息输出到stderr;stdout仅包含事件。每行输出后立即刷新,因此管道能即时看到事件。
## 绑定命令
首先了解你的踏板发送什么。运行`fcbnerd -f text`并按下开关:
``console
$ fcbnerd -f text
16:30:41.115 pc channel=1 program=7 bind=pc:1:7 [USB MIDI Interface]
16:30:41.115 cc channel=1 controller=20 value=127 bind=1:20:127 [USB MIDI Interface]
然后将命令绑定到该模式:
``sh
fcbnerd –bind ‘1:20:127=open ~/Downloads’
绑定格式为`模式=命令`。第一个`=`之后的所有内容都是命令,因此命令本身可包含`=`和`:`。可多次使用`--bind`。每个匹配消息的绑定按给定顺序启动,且同时运行。
| 模式 | 匹配项 |
|---|---|
| `CHANNEL:CONTROLLER:VALUE` | 控制变化,例如`1:20:127`。`cc:1:20:127`同样有效。 |
| `pc:CHANNEL:PROGRAM` | 程序变更,例如`pc:1:7`。 |
任何数字可用`*`代替:`1:27:*`匹配通道1上控制器27的所有值,这是绑定表情踏板的方式。
命令通过`/bin/sh -c`或你用`--shell`指定的shell在后台运行。其标准输入为`/dev/null`。标准输出发送到fcbnerd的stderr,以免污染事件流;使用`--quiet`时则发送到stdout。它们可访问以下环境变量:
| 变量 | 说明 |
|---|---|
| `MIDI_TYPE` | `cc`或`pc` |
| `MIDI_CHANNEL` | 1–16 |
| `MIDI_CONTROLLER`、`MIDI_VALUE` | 用于`cc` |
| `MIDI_PROGRAM` | 用于`pc` |
| `MIDI_SOURCE` | MIDI源名称 |
``sh
# 表情踏板设置输出音量
fcbnerd -q --bind '1:27:*=osascript -e "set volume output volume $((MIDI_VALUE * 100 / 127))"'
每次踩踏都会运行命令,因此快速连踩两次即使第一次运行未完成也会执行两次。这也意味着每条匹配消息都会启动一个shell。避免对嘈杂设备使用*:*:127或pc:*:*等宽泛模式。
踏板扫描是例外。扫描每秒发送数十个值,因此对于含*值的绑定,每个控制器(通道和控制器号)同时只有一个命令副本运行。运行期间,fcbnerd仅保留该控制器的最新值并在下次运行,从而控制shell数量并最终停在踏板最后位置。若命令5秒后仍在运行,fcbnerd会在stderr中说明。
非零退出码的命令会将其绑定和退出状态打印到stderr。停止fcbnerd(Ctrl+C、kill、关闭终端或stdout关闭)会向仍在运行的所有命令发送SIGTERM,包括其启动的进程。
Shell函数
交互式shell中的函数和别名在sh -c中不会加载。在bash中,导出函数使其可见(macOS的/bin/sh是bash,因此默认shell能看到):
greet() { say "preset $MIDI_PROGRAM"; }
export -f greet
fcbnerd -q --bind 'pc:1:*=greet'
zsh无法导出函数。将其放入文件并用zsh加载:--shell /bin/zsh --bind 'pc:1:*=source ~/.fcbnerd.zsh && greet'。
开关功能
FCB1010在松开开关时不发送任何消息(参见FCB1010说明),因此绑定仅在按下时触发。要实现开关功能,需在命令中维护状态,例如通过切换/tmp下的文件。
输出
fcbnerd listen每行打印一个JSON对象。每个对象包含type、source(MIDI源显示名称)和time(fcbnerd收到消息的时间:ISO 8601格式,UTC时间,毫秒)。通道为1–16;音符、控制器、程序、力度和压力值为原始0–127 MIDI值。
type | 额外字段 | 说明 |
|---|---|---|
pc | channel、program | 程序变更。program在线路传输中为0起始。 |
cc | channel、controller、value | 控制变化:开关和表情踏板。 |
note_on | channel、note、velocity | |
note_off | channel、note、velocity | 力度为0的音符开也发出此事件。 |
poly_pressure | channel、note、pressure | |
channel_pressure | channel、pressure | |
pitch_bend | channel、value | 0–16383,中心值8192。 |
sysex | length、data | data为小写十六进制,包含f0…f7帧;length统计这些字节。 |
connected | 源出现并被监听。始终在该源事件之前。 | |
disconnected | 源消失。已发出的消息可能仍在传输中。 |
不发出系统实时消息(MIDI时钟等)和系统通用消息(歌曲位置、MTC)。未来版本可能添加新事件类型或字段;现有字段含义不会改变。消费者应忽略无法识别的类型和字段。
及时读取消费流。如果消费者停止读取,fcbnerd会在内存中排队事件,并在恢复读取时全部传递,因此停滞的消费者会响应一系列过时的踩踏事件。
fcbnerd list --format json输出不同结构,每源一行:{"type":"source","name":"UM-ONE","id":-1234567}。id是CoreMIDI唯一标识。
示例
Shell与jq
程序0切换到下一个空间,程序1切换到上一个。这需要多个空间,系统设置→键盘→键盘快捷键→调度中心中启用(默认)“向左/右移动一个空间”快捷键,且你的终端应用需具备辅助功能权限和自动化权限以控制系统事件。首次使用时macOS会请求自动化权限。
``sh
fcbnerd | jq –unbuffered -r ‘select(.type == “pc”) | .program’ |
while read -r program; do
case “$program” in
0) osascript -e ‘tell application “System Events” to key code 124 using control down’ ;;
1) osascript -e ‘tell application “System Events” to key code 123 using control down’ ;;
esac
done
### Hammerspoon
程序0切换播放/暂停,CC 27的表情踏板设置输出音量。输出可能分段到达,需缓冲至换行。路径适用于Apple Silicon;Intel上的Homebrew安装到`/usr/local/bin`。
```lua
local buffer = ""
fcbnerd = hs.task.new("/opt/homebrew/bin/fcbnerd", nil, function(_, stdout, _)
buffer = buffer .. stdout
for line in buffer:gmatch("([^\n]*)\n") do
local event = hs.json.decode(line)
if event and event.type == "pc" and event.program == 0 then
hs.eventtap.event.newSystemKeyEvent("PLAY", true):post()
hs.eventtap.event.newSystemKeyEvent("PLAY", false):post()
elseif event and event.type == "cc" and event.controller == 27 then
hs.audiodevice.defaultOutputDevice():setVolume(event.value / 127 * 100)
end
end
buffer = buffer:match("[^\n]*$")
return true
end)
fcbnerd:start()
FCB1010说明
消费者需处理的踏板特性:
- 按下发送一条消息,松开不发送任何内容。开关功能(首次按“开”,再次按“关”)需由消费者跟踪。
- 出厂预设根据当前预设从同一开关发送不同CC编号。运行
fcbnerd -f text,按下计划使用的每个开关,记录其发送内容。 - 按下开关也会重新发送该预设的表情踏板值,因此踏板控制器上的每个
cc不一定代表脚部移动。 - 表情踏板无法达到完整的0–127范围。部分行程不发送消息,扫描约覆盖三分之二的值,因此需按实际范围重新缩放。
- 踏板仅有5针DIN MIDI。你需要USB MIDI接口,其显示为
source名称。
开发
``sh
swift build
swift test # 解码器、格式化器和绑定测试
.build/debug/fcbnerd simulate & # 模拟踏板
.build/debug/fcbnerd –format text # 观察输出
`Sources/FCBNerdCore`解码CoreMIDI的Universal MIDI包、格式化输出并解析绑定。它不依赖CoreMIDI,因此测试无需硬件。
`Sources/fcbnerd`是CLI:CoreMIDI连接、热插拔和模拟器。
发布时,在`Sources/fcbnerd/main.swift`中提升`version`,提交并推送匹配标签:
``sh
git tag -a v1.2.3 -m "fcbnerd 1.2.3" && git push origin v1.2.3
发布工作流将测试、发布含通用二进制文件的GitHub Release,并更新JamesRyanATX/homebrew-tap (https://github.com/JamesRyanATX/homebrew-tap)中的formula。
许可证
MIT
相似文章
Show HN: Kinesis – 使用 Meta Neural Band 控制你的 Mac
Kinesis 是一个开源工具,允许用户使用 Meta Neural Band 的手势来控制 Mac,包括在桌面之间滑动、调整音量或亮度。
Show HN: 一只被vibecode气味吸引的桌面苍蝇
一个macOS桌面应用,使用来自FlyWire的真实神经数据模拟果蝇大脑,能够检测'vibecode'标记来引导苍蝇的移动。
MIDIpad
MIDIpad 是一款 macOS 应用程序,可将游戏手柄转换为富有表现力的 MIDI 控制器,用于数字音频工作站,具有和弦和鼓点音序器模式。
展示HN:公共Muscriptor实例(最新、最强大的Audio-to-MIDI模型)
Muscriptor的公共实例,作为最新、最强大的Audio-to-MIDI模型,现已可用,能通过GPU加速将任何歌曲转换为钢琴MIDI。
Show HN: 我们怀念Winamp,因此为macOS构建了一款音频播放器
一款名为180db的新macOS音频播放器发布,其灵感来自Winamp,专为音乐人和DJ设计,具备变调、布局自定义等功能。