JamesRyanATX/fcbnerd: Do things with a Behringer FCB1010 MIDI pedalboard in Mac OS · GitHub
Use a MIDI foot controller as an additional keyboard for yourMac fcbnerd
links to your MIDI sources and either runs a shell command when a.
footswitch or pedal sends out a message you have actually bound, or prints one JSON item.
per line for every single message so another program can choose what a stomp.
methods.
$ fcbnerd -q-- bind ' 1:20:127= open ~/Downloads'-- bind ' pc:1:0= state hey there'
Or stream whatever for another program to manage:
$ fcbnerd
{"type":" linked"," source":" UM-ONE"," time":" 2026-09-14T20:01:00.120 Z"}
{"type":" pc"," channel":1," program":0," source":" UM-ONE"," time":" 2026-09-14T20:01:02.345 Z"}
{"type":" cc"," channel":1," controller":30," worth":84," source":" UM-ONE"," time":" 2026-09-14T20:01:03.910 Z"}
Built for the Behringer FCB1010, however absolutely nothing in it is FCB1010-specific: any.
CoreMIDI source works.
Anything that acts upon your Mac, like pushing secrets or running scripts, requirements.
authorizations that sandboxed apps can’t get, and every user desires a various.
set of actions anyhow. fcbnerd just checks out MIDI, which requires no authorizations.
The actions come from your shell, or to a tool that currently has the gain access to,.
such as Hammerspoon or Keyboard Maestro.
brew trust-- tap jamesryanatx/tap # Homebrew 7+ will not pack third-party taps up until you trust them
brew set up JamesRyanATX/tap/fcbnerd
Or from source without Homebrew (Xcode or the Swift toolchain, macOS 13+):
speedy construct -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 replicate.
listen(default) links to every MIDI source, or just those whose.
name includes-- source, and streams occasions up until interrupted. It follows.
hotplug: disconnect the user interface mid-set and plug it back in, and the stream.
continues withdetached/linkedlines.listprints the sources readily available today.replicatereleases a virtual MIDI source calledfcbnerd simulator
that plays artificial presses, a pedal sweep and a sysex message on a loop.
Run it in one terminal andfcbnerdin another to construct a customer without any.
pedal connected.-- format textprints lined up columns for eyeballing, consisting of a.
bind =pattern for each message you can bind. Scripts ought to utilize the.
default JSON; the text design might alter.-- bindruns a command when a message matches; see listed below.-- peacefulstops printing occasions, leaving just the bound commands.-- shell courseselects the shell that runs bound commands (default.
/ bin/sh).
Status messages go to stderr; stdout brings just occasions. Each line is.
flushed as quickly as it’s composed, so pipelines see occasions instantly.
First discover what your pedal sends out. Run fcbnerd -f text and push the.
switch:
$ 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 worth= 127 bind= 1:20:127 [USB MIDI Interface]
Then bind a command to that pattern:
fcbnerd-- bind ' 1:20:127= open ~/Downloads'
A binding is PATTERN= COMMAND Everything after the very first = is the command,.
so it can consist of = and : itself. Use -- bind as lot of times as you like.
Every binding that matches a message begins, in the order offered, and they run.
at the exact same time.
| Pattern | Matches |
|---|---|
CHANNEL: CONTROLLER: WORTH |
Control modification, e.g. 1:20:127 cc:1:20:127 likewise works. |
pc: CHANNEL: PROGRAM |
Program modification, e.g. pc:1:7 |
Any number can be *: 1:30:* is every worth of controller 30 on channel 1,.
which is how you bind an expression pedal.
Commands run in the background through / bin/sh -c, or the shell you offer.
with -- shell Their stdin is / dev/null Their stdout goes to fcbnerd’s.
stderr, so it can’t corrupt the occasion stream; with -- peaceful it goes to.
stdout. They see these environment variables:
| Variable | |
|---|---|
MIDI_TYPE |
cc or pc |
MIDI_CHANNEL |
1– 16 |
MIDI_CONTROLLER, MIDI_VALUE |
For cc |
MIDI_PROGRAM |
For pc |
MIDI_SOURCE |
MIDI source name |
# Expression pedal sets output volume
fcbnerd -q-- bind ' 1:30: *= osascript -e "set volume output volume $(( MIDI_VALUE * 100/ 127))"'
Every stomp runs the command, so 2 fast presses run it two times even if the.
initially run hasn’t ended up. That likewise implies every matching message begins a.
shell. Keep broad patterns like *: *:127 or pc: *:* far from loud gadgets.
Pedal sweeps are the exception. A sweep sends out lots of worths a 2nd, so.
for a binding with a * worth, just one copy of the command performs at a time.
for each control (channel and controller). While it runs, fcbnerd keeps just.
that control’s most recent worth and runs it next, which keeps the shell count down.
and still ends on the pedal’s last position. If a command is still running.
after 5 seconds, fcbnerd states so on stderr.
A command that exits non-zero gets its binding and exit status printed to.
stderr. Stopping fcbnerd (Ctrl+ C, eliminate, closing the terminal, or a closed.
stdout) sends out SIGTERM to any command still running, consisting of procedures it.
begun.
Functions and aliases from your interactive shell aren’t filled in sh -c
In celebration, export a function to make it noticeable (macOS’s / bin/sh is celebration, so.
the default shell sees it):
greet() {state " predetermined $ MIDI_PROGRAM";}
export -f welcome.
fcbnerd -q-- bind ' pc:1: *= greet'
zsh can’t export functions. Put them in a file and source it with zsh:.
-- shell/ bin/zsh-- bind 'pc:1: *= source ~/. fcbnerd.zsh && & greet'
The FCB1010 sends out absolutely nothing when you release a switch (see.
FCB1010 notes), so a binding fires on journalism just.For
on/off habits, keep the state in the command, for instance by toggling a.
file in / tmp
fcbnerd listen prints one JSON item per line. Every item has type,.
source (the MIDI source’s screen name) and time (when fcbnerd gotten.
the message: ISO 8601, UTC, milliseconds). Channels are 1– 16; note,.
controller, program, speed and pressure worths are the raw 0– 127 MIDI.
worths.
type |
Extra fields | Notes |
|---|---|---|
pc |
channel, program |
Program modification. program is 0-based on the wire. |
cc |
channel, controller, worth |
Control modification: switches and expression pedals. |
note_on |
channel, note, speed |
|
note_off |
channel, note, speed |
Also produced for note-on with speed 0. |
poly_pressure |
channel, note, pressure |
|
channel_pressure |
channel, pressure |
|
pitch_bend |
channel, worth |
0– 16383, center 8192. |
sysex |
length, information |
information is lowercase hex consisting of the f0 … f7 framing; length counts those bytes. |
linked |
A source appeared and is being listened to. Always precedes that source’s occasions. | |
detached |
A source disappeared. A message currently in flight might still follow it. |
System real-time messages (MIDI clock and so on) and system typical messages.
( tune position, MTC) are not produced. New occasion types or fields might be included.
in future variations; existing ones will not alter significance. Consumers should.
neglect types and fields they do not acknowledge.
Read the stream without delay. If a customer stops reading, fcbnerd lines occasions.
in memory and provides them all when checking out resumes, so a stalled customer.
will act upon a burst of stagnant presses.
fcbnerd list-- format json prints a various shape, one line per source:.
{"type":" source"," name":" UM-ONE"," id": -1234567} id is the CoreMIDI.
special ID.
examples/developer.sh is a total, commented.
setup for software application engineers: 10 switches for running tests, waiting on CI,.
syncing the branch, silencing the mic and more, plus an expression pedal on.
output volume. Run it with DRY_RUN= 1 initially to see what each switch would do.
Program 0 switches to the next Space, and program 1 to the previous one.This
requirements more than one Space, the “Move left/right an area” faster ways.
made it possible for (the default) in System Settings → Keyboard → Keyboard Shortcuts →.
Mission Control, and for your terminal app both Accessibility consent and.
Automation consent to controlSystem Events macOS requests theAutomation
consent the very first time.
fcbnerd | jq-- unbuffered -r ' choose(. type == "pc") |. program' |
while read -r program; do
case "$ program" in
0) osascript -e ' inform application "System Events" to essential code 124 utilizing control down';;.
1) osascript -e ' inform application "System Events" to essential code 123 utilizing control down';;.
esac
done
Program 0 toggles play/pause, and an expression pedal on CC 30 sets the output.
volume. Output can get here in.
partial pieces, so buffer up until a newline. The course is for Apple Silicon;.
Homebrew on Intel sets up to / usr/local/bin
regional buffer = ""
fcbnerd = hs job brand-new("/ opt/homebrew/bin/ fcbnerd", nil, function( _, stdout, _).
buffer = buffer stdout
for line in buffer: gmatch("([^n] *) n") do
regional occasion = hs json translate( line).
if occasion and occasion type = = " pc" and occasion program = = 0 then
hs eventtap occasion brand-newSystem KeyEvent(" PLAY", real): post().
hs eventtap occasion brand-newSystem KeyEvent(" PLAY", incorrect): post().
elseif occasion and occasion type = = " cc" and occasion controller = = 30 then
hs audiodevice defaultOutput Gadget(): setVolume( occasion worth / 127 * 100).
end
end
buffer = buffer: match("[^n] *$").
return real
end).
fcbnerd: start()
Things about the pedal that customers require to manage:
- A press sends out one message and releasing sends out absolutely nothing. On/ off habits.
( very first press “on”, 2nd “off”) needs to be tracked by the customer. - The factory presets send out various CC numbers from the exact same switch.
depending upon which predetermined is active. Runfcbnerd -f text, press each.
switch you prepare to utilize, and note what it sends out. - Pressing a switch likewise re-sends that predetermined’s expression-pedal worths, so.
not everyccon a pedal’s controller implies the foot moved. - The expression pedals do not reach the complete 0– 127 variety. Part of the travel.
sends out absolutely nothing and the sweep covers approximately two-thirds of the worths, so.
rescale to the variety you in fact see. - The pedal has 5-pin DIN MIDI just. You require a USB MIDI user interface, which.
appears as thesourcename.
speedy construct.
swift test # decoder, formatter and binding tests
. build/debug/fcbnerd replicate && # phony pedal build/debug/fcbnerd-- format text # see it
Sources/ FCBNerdCore deciphers CoreMIDI’s Universal MIDI Packets, formats.
output and parses bindings. It has no CoreMIDI reliance, so its trial run.
without hardware.
Sources/ fcbnerd is the CLI: CoreMIDI connections, hotplug and the.
simulator.
To release, bump variation in Sources/ fcbnerd/main. swift, dedicate, and push a.
matching tag:
git tag -a v1.2.3 -m " fcbnerd 1.2.3" &&& & git push origin v1.2.3
The release workflow tests, releases a.
GitHub Release with a universal binary, and updates the formula in.
JamesRyanATX/homebrew-tap
MIT


