展示HN:在macOS上使用Behringer FCB1010 MIDI脚踏板的宏功能

Hacker News Top 工具

摘要

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额外字段说明
pcchannel、program程序变更。program在线路传输中为0起始。
ccchannel、controller、value控制变化:开关和表情踏板。
note_onchannel、note、velocity
note_offchannel、note、velocity力度为0的音符开也发出此事件。
poly_pressurechannel、note、pressure
channel_pressurechannel、pressure
pitch_bendchannel、value0–16383,中心值8192。
sysexlength、datadata为小写十六进制,包含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

相似文章

MIDIpad

Product Hunt

MIDIpad 是一款 macOS 应用程序,可将游戏手柄转换为富有表现力的 MIDI 控制器,用于数字音频工作站,具有和弦和鼓点音序器模式。