midi-harbor/docs/installation.md
2026-09-28 13:59:10 -05:00

203 lines
9.4 KiB
Markdown

# Installation
One binary, `midi-harbor`, contains the daemon, the command line, and optionally the graphical
interface. It comes as a package, or can be built from source.
## Installing a package
**macOS**: open the disk image and drag Midi Harbor to Applications. Opening the app shows the
graphical interface, which offers to start the daemon at login. From a terminal, the same binary
is at `/Applications/Midi Harbor.app/Contents/MacOS/midi-harbor`.
The app is signed with a Developer ID and notarized by Apple, so it opens like any other
downloaded app. A copy built from source is signed ad hoc instead: the first time it is opened
macOS refuses, saying Apple could not verify it is free of malware. Open **System Settings →
Privacy & Security**, scroll to the message that Midi Harbor was blocked, and choose **Open
Anyway**; macOS asks once more, and opens it normally from then on.
**Mac App Store**: the App Store build, which needs macOS 13 or newer, runs differently. The app
starts its own daemon and lives in the menu bar: closing the window, or ⌘Q, leaves everything
running with Midi Harbor's item in the menu bar, and **Quit Midi Harbor** there, or ⌥⌘Q, stops it.
Instead of a launchd service, **Start at login** in Settings starts it at login, opening the window
only if it was open when Midi Harbor last quit. Its setup is kept inside the app's container, so
`midi-harbor config path`, run from the app's own binary, prints a path under
`~/Library/Containers/com.mrgeckosmedia.MidiHarbor`. Of the `service` commands, only
`service stop` works there.
**Debian and Ubuntu**: `sudo apt install ./midi-harbor_<version>_<arch>.deb`, or the
`midi-harbor-headless` package for a machine without a display.
**Fedora, RHEL and other RPM distributions**: `sudo dnf install ./midi-harbor-<version>-1.<arch>.rpm`,
or `midi-harbor-headless`.
The Linux packages need glibc 2.35 or newer: Debian 12, Ubuntu 22.04, Fedora 36, RHEL 10 and
anything newer. On RHEL 9 and its rebuilds, build from source. The packages recommend Avahi and
BlueZ. Installing a package does not start anything. Each user who wants the daemon at login runs
`midi-harbor service install --start`.
**Windows**: unpack `midi-harbor-<version>.windows-amd64.zip` somewhere it will stay, such as
`%LOCALAPPDATA%\Programs\Midi Harbor`; the service remembers where it is. There is no installer.
The executable is not signed, so the first time it runs Windows may show "Windows protected your
PC"; choose **More info**, then **Run anyway**.
**Without installing**: each release also has a `.tar.gz` of the binary for Linux, and a
`midi-harbor-headless` one for Linux and for each kind of Mac. On the Mac the graphical interface
comes only in the app. The headless binary is not signed, so macOS refuses to run one downloaded
through a browser until the download's quarantine is removed with
`xattr -d com.apple.quarantine midi-harbor`.
`packaging/README.md` describes how the packages are built.
## Building from source
### Requirements
**Rust** 1.96 or newer.
**macOS**: the Xcode command line tools (`xcode-select --install`). CoreMIDI, CoreBluetooth and
Bonjour ship with the system.
**Linux**: a C toolchain and the development files for ALSA, D-Bus and Avahi, plus libclang, which
the Avahi bindings are generated with. On Debian and Ubuntu:
```bash
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, where RHEL and its rebuilds need the CodeReady Builder repository enabled
first:
```bash
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
```
A build without the graphical interface, `--no-default-features`, needs neither of the second
lines.
At run time, Linux needs:
- the ALSA sequencer (`snd-seq`), which every desktop distribution loads;
- `avahi-daemon` running, for other machines to find this one's network ports;
- BlueZ 5.50 or newer, for Bluetooth;
- systemd, to run the daemon at login. Without it, run the daemon in the foreground.
Without Avahi, network ports still work. Other machines just have to connect to them by address.
**Windows**: Windows builds are cross-compiled from macOS or Linux with mingw-w64:
```bash
rustup target add x86_64-pc-windows-gnu
brew install mingw-w64 # or apt install gcc-mingw-w64-x86-64
cargo build --release --target x86_64-pc-windows-gnu
```
The linker is set in `.cargo/config.toml`. The binary is
`target/x86_64-pc-windows-gnu/release/midi-harbor.exe`.
At run time, Windows 10 or 11 (tested on Windows 11) needs Windows MIDI Services for virtual
ports. Windows 11 includes it from its late-2026 update; before that, install Microsoft's
[Windows MIDI Services SDK Runtime and Tools](https://github.com/microsoft/MIDI/releases). Before
the update, closing a virtual port stops the Windows MIDI Service answering until it is
restarted; [Platforms](platforms.md#virtual-ports-on-windows) says how. Everything else Midi
Harbor needs is part of Windows.
### Building
```bash
cargo build --release # with the graphical interface
cargo build --release --no-default-features # without it
```
The build without the graphical interface leaves out the whole GUI toolkit, not just the window.
Use it on servers and machines with no display. Building the graphical interface on Linux needs
libcosmic's own build dependencies as well.
To install the binary into `~/.cargo/bin`:
```bash
cargo install --path . # or add --no-default-features
```
### Testing
```bash
make test # unit tests: wire formats, external formats, algorithms
make test-integration # the daemon, CLI and protocols as a whole, over real files and sockets
make test-live # tests needing CoreMIDI, ALSA, WinMM, a radio or a session peer
```
The first two need nothing but the build dependencies above. `make test-live` runs the tests that
need something real on this machine, one at a time; each names what it needs, and fails without
it.
## Running the daemon
Nothing connects until the daemon is running. There are two ways to run it.
**At login, as a service.** This is the normal way:
```bash
midi-harbor service install --start
midi-harbor service status
```
`service install` registers the binary it was run from:
| | Registration | Controlled with | Log |
|---|---|---|---|
| macOS | a launchd agent, `~/Library/LaunchAgents/com.mrgeckosmedia.MidiHarbor.daemon.plist` | `launchctl` | `~/Library/Logs/midi-harbor/daemon.log` |
| Linux | a systemd user unit, `~/.config/systemd/user/midi-harbor.service` | `systemctl --user` | `journalctl --user -u midi-harbor` |
| Windows | a Task Scheduler task, "Midi Harbor", started at sign-in | Task Scheduler | `%LOCALAPPDATA%\midi-harbor\logs\daemon.log` |
On macOS and Windows the daemon writes the log file itself. Past 10 MB it moves the file to
`daemon.log.1`, replacing the one before, and starts again, so the two never take more than 20 MB.
On macOS, Console.app shows it under Log Reports. A registration made before this log existed has
none: run `service install` again to add it.
Running `install` again updates the registration in place. It does not add a second one. If the
binary has since moved, `service status` reports the registration as stale, and `install` repairs
it. `service stop` and `service start` stop and start the daemon without changing the
registration.
**In the foreground**, for trying things out or for a machine without a service manager:
```bash
midi-harbor daemon
```
It logs to the terminal and stops on Ctrl-C, releasing any notes still sounding as it goes. Add
`-v` or `-vv` for more detail, or `--log-file <PATH>` to log to a file that rolls over the same
way as the service's.
Only one daemon runs per user. The command line finds it through a socket in the user's runtime
directory (`$XDG_RUNTIME_DIR/midi-harbor/daemon.sock` on Linux, the per-user temporary directory
on macOS). `--socket` points a command, or a second daemon, somewhere else. The socket is readable
only by its owner, and the daemon is never reachable over the network.
On Windows the daemon listens on a named pipe with a random name instead, and writes that name
to `daemon.sock` in the user's temporary directory, where the command line reads it. The pipe
refuses connections from other machines. On Windows the task runs the daemon under a supervisor
that starts it again after a crash, and `service stop` asks the daemon to stop rather than ending
it, so held notes are released first.
## Bluetooth on macOS
macOS asks for permission before a program may use Bluetooth, and grants it to an app. Installed
from the disk image, the daemon runs from inside Midi Harbor.app and should be asked about as
Midi Harbor. If Bluetooth is refused to it, run `midi-harbor daemon` from a terminal, which uses
the terminal application's permission instead. A bare binary registered with `service install`
has neither, so on macOS install the service from the app. `midi-harbor capabilities` reports
which Bluetooth roles are usable, and why not when they are not.
## Removing it
```bash
midi-harbor service uninstall
```
This stops the daemon and removes its registration. The configuration file is left where it is
(see [Configuration file](configuration.md)), so installing again brings the same setup back.
Delete it by hand to start from nothing.