Virtual MIDI ports, hardware, RTP-MIDI and Bluetooth MIDI for macOS, Linux and Windows.
Find a file
James Coleman 43f7b8916b fix(appimage): install the desktop entry so the window gets its icon
- A Wayland desktop finds a window's icon by looking up its application ID among the installed desktop entries. An AppImage carries its entry and icon inside its own tree, where no desktop looks, so its window showed the generic Wayland icon and Midi Harbor was missing from the application menu.
- Run from an AppImage, the window now installs com.mrgeckosmedia.MidiHarbor.desktop under $XDG_DATA_HOME/applications and the icon under icons/hicolor/scalable/apps before it opens. Exec is rewritten to the AppImage file, quoted as the Desktop Entry Specification requires, and each file is written only when it differs, so a moved AppImage is followed.
- TryExec names the AppImage file, so desktops stop offering the entry once the file is deleted, which is how an AppImage is removed.
- Nothing is installed when a directory in XDG_DATA_DIRS already holds the entry: one under the user's directory takes precedence and would point a package's menu item at the AppImage.
2026-10-02 12:32:08 -05:00
.cargo First commit 2026-09-28 13:59:10 -05:00
.claude/skills First commit 2026-09-28 13:59:10 -05:00
.specify docs(specs): drop the spec names used before the renumbering 2026-09-29 14:35:33 -05:00
crates fix(appimage): install the desktop entry so the window gets its icon 2026-10-02 12:32:08 -05:00
docs fix(appimage): install the desktop entry so the window gets its icon 2026-10-02 12:32:08 -05:00
fuzz feat(network): follow a machine's session and forget removed ones 2026-10-02 11:56:20 -05:00
packaging feat(update): say when the daemon is another build and update it on request 2026-10-02 11:56:27 -05:00
proto/midiharbor/v1 feat(update): say when the daemon is another build and update it on request 2026-10-02 11:56:27 -05:00
scripts First commit 2026-09-28 13:59:10 -05:00
specs fix(appimage): install the desktop entry so the window gets its icon 2026-10-02 12:32:08 -05:00
src First commit 2026-09-28 13:59:10 -05:00
tests feat(update): say when the daemon is another build and update it on request 2026-10-02 11:56:27 -05:00
.gitignore First commit 2026-09-28 13:59:10 -05:00
.goreleaser.yaml feat(update): say when the daemon is another build and update it on request 2026-10-02 11:56:27 -05:00
AGENTS.md First commit 2026-09-28 13:59:10 -05:00
build.rs First commit 2026-09-28 13:59:10 -05:00
Cargo.lock feat(network): follow a machine's session and forget removed ones 2026-10-02 11:56:20 -05:00
Cargo.toml feat(network): follow a machine's session and forget removed ones 2026-10-02 11:56:20 -05:00
clippy.toml First commit 2026-09-28 13:59:10 -05:00
Icon.svg build(icon): give both cable strands and the MIDI pins a glow 2026-10-02 11:55:25 -05:00
LICENSE.txt First commit 2026-09-28 13:59:10 -05:00
Makefile feat(update): say when the daemon is another build and update it on request 2026-10-02 11:56:27 -05:00
README.md feat(release): publish an AppImage for each Linux architecture 2026-09-29 14:35:51 -05:00
rust-toolchain.toml First commit 2026-09-28 13:59:10 -05:00
rustfmt.toml First commit 2026-09-28 13:59:10 -05:00
VERSION First commit 2026-09-28 13:59:10 -05:00

midi-harbor

Midi Harbor manages MIDI connections on macOS, Linux and Windows: virtual ports other applications can use, attached MIDI hardware, RTP-MIDI network sessions to other computers, and Bluetooth LE MIDI devices. A daemon owns every connection and repairs it on its own. A network session that drops is reconnected, hardware that is unplugged and plugged back in picks up where it left off, and notes sounding when a link went away are released rather than left ringing.

The command line and the graphical interface are both clients of the daemon, so closing either changes nothing.

Install

Download a package or archive from the releases, or build this project. midi-harbor-headless leaves out the graphical interface, for machines without a display.

sudo apt install ./midi-harbor_<version>_<arch>.deb    # Debian and Ubuntu
sudo dnf install ./midi-harbor-<version>-1.<arch>.rpm    # Fedora and RHEL
chmod +x Midi-Harbor-<version>-x86_64.AppImage              # any other distribution

The release builds need glibc 2.35 or newer, so RHEL 9 and its rebuilds must build from source.

The Windows executable is not signed, so it warns the first time it runs; Installation says how to let it run.

On Windows, virtual ports need Windows MIDI Services. Windows 11 includes it from its late-2026 update; before that, install Microsoft's Windows MIDI Services SDK Runtime and Tools.

Building

Building needs Rust 1.96 or newer. On Linux it also needs the ALSA, D-Bus and Avahi development files and libclang, and for the graphical interface the xkbcommon and Wayland development files.

On Debian and Ubuntu:

sudo apt install build-essential pkg-config libasound2-dev libdbus-1-dev \
                 libavahi-client-dev libclang-dev
sudo apt install libxkbcommon-dev libwayland-dev    # for the graphical interface

On Fedora and RHEL (enable CodeReady Builder first on RHEL and its rebuilds):

sudo dnf install gcc pkgconf-pkg-config alsa-lib-devel dbus-devel avahi-devel clang-devel
sudo dnf install libxkbcommon-devel wayland-devel    # for the graphical interface

Then:

cargo build --release                        # with the graphical interface
cargo build --release --no-default-features  # without it

Windows builds are cross-compiled with mingw-w64:

rustup target add x86_64-pc-windows-gnu
cargo build --release --target x86_64-pc-windows-gnu

Release packages for every platform are built with GoReleaser in Docker, through make snapshot and make release.

Running as a service

The daemon registers itself with launchd, a systemd user unit, or Task Scheduler, and runs at every login:

midi-harbor service install --start
midi-harbor service status

Running from the command line

To try things out, or to see more of what the daemon is doing, run it in the foreground:

midi-harbor daemon -vv

Config

The setup lives in one YAML file per user, which the daemon writes as things change. midi-harbor config path prints where it is. It can be written by hand; only names and kinds are required:

endpoints:
  - name: Sequencer Bus
    kind: virtual_port
  - name: Studio
    kind: network_port
routes:
  - from: Sequencer Bus
    to: Studio

Run midi-harbor config reload after editing it while the daemon runs.

Usage

Every command has help:

midi-harbor --help

Run with no command, midi-harbor opens the graphical interface.

A basic setup that sends a local virtual port to another computer:

midi-harbor port create "Sequencer Bus"
midi-harbor network create "Studio"
midi-harbor network discover
midi-harbor network connect "Studio" "Stage Mac"
midi-harbor route create "Sequencer Bus" "Studio"

MIDI played into "Sequencer Bus" now reaches "Stage Mac", and keeps reaching it across sleep, network changes, and either machine restarting.

Testing

make test                # unit tests
make test-integration    # the daemon, CLI and protocols over real files and sockets
make test-live           # tests needing real MIDI, a Bluetooth radio or a session peer