Skip to content

Commit

Permalink
Merge branch 'midirouter'
Browse files Browse the repository at this point in the history
  • Loading branch information
davidmoreno committed Dec 12, 2023
2 parents fc7debc + 950a4a7 commit 70861b0
Show file tree
Hide file tree
Showing 86 changed files with 19,479 additions and 13,871 deletions.
31 changes: 29 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,33 @@ cmake_minimum_required(VERSION 3.2)
add_definitions("-std=gnu++17 -Wall -Werror")
# set(CMAKE_POSITION_INDEPENDENT_CODE ON)

set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fstack-protector-strong")
# set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fstack-protector-strong -fsanitize=address")
# set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer -fstack-protector-strong")
set (CMAKE_LINKER_FLAGS_DEBUG "${CMAKE_LINKER_FLAGS_DEBUG} -fno-omit-frame-pointer")

message(STATUS "Build type ${CMAKE_BUILD_TYPE}")

# if debug build add -O0
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_definitions ("-O0 -g")
else()
add_definitions ("-O2")
endif()



# Add option to enable/disable tests
option(ENABLE_TESTS "Enable tests" ON)
# option to enable precompiled headers
option(ENABLE_PCH "Enable precompiled headers" ON)

if (ENABLE_PCH)
# show a log message
message(STATUS "Precompiled headers enabled")
else(ENABLE_PCH)
# show a log message
message(STATUS "Precompiled headers disabled")
endif(ENABLE_PCH)

include(FindPkgConfig)
pkg_check_modules(AVAHI REQUIRED avahi-client)
Expand All @@ -25,4 +49,7 @@ message(STATUS "Version ${RTPMIDID_VERSION}")

add_subdirectory(lib)
add_subdirectory(src)
add_subdirectory(tests)

if (ENABLE_TESTS STREQUAL "ON")
add_subdirectory(tests)
endif()
57 changes: 40 additions & 17 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,20 +1,28 @@
PORT := 10000
# Port for test run
PORT:=10000
# Number of jobs for make
JOBS:=8

# To easy change to clang, set CXX
CMAKE_EXTRA_ARGS := -DCMAKE_CXX_COMPILER=${CXX} -GNinja -DENABLE_PCH=OFF


.PHONY: help
help:
@echo "Makefile for rtpmidid"
@echo
@echo " build -- Creates the build directory and builds the rtpmidid"
@echo " run -- builds and runs the daemon"
@echo " setup -- Creates the socket control file"
@echo " clean -- Cleans project"
@echo " deb -- Generate deb package"
@echo " test -- Runs all test"
@echo " install -- Installs to PREFIX or DESTDIR (default /usr/local/)"
@echo " man -- Generate man pages"
@echo " build -- Creates the build directory and builds the rtpmidid"
@echo " build-dev -- Creates the build directory and builds the rtpmidid for debugging"
@echo " run -- builds and runs the daemon"
@echo " setup -- Creates the socket control file"
@echo " clean -- Cleans project"
@echo " deb -- Generate deb package"
@echo " test -- Runs all test"
@echo " install -- Installs to PREFIX or DESTDIR (default /usr/local/)"
@echo " man -- Generate man pages"
@echo
@echo " gdb -- Run inside gdb, to capture backtrace of failures (bt). Useful for bug reports."
@echo " capture -- Capture packets with tcpdump. Add this to bug reports."
@echo " gdb -- Run inside gdb, to capture backtrace of failures (bt). Useful for bug reports."
@echo " capture -- Capture packets with tcpdump. Add this to bug reports."
@echo
@echo "Variables:"
@echo
Expand All @@ -26,14 +34,24 @@ build: build/bin/rtpmidid

build/bin/rtpmidid: src/* tests/* CMakeLists.txt
mkdir -p build
cd build && cmake .. -DCMAKE_BUILD_TYPE=Release
cd build && make -j
cd build && cmake .. -DCMAKE_BUILD_TYPE=Release $(CMAKE_EXTRA_ARGS)
cd build && ninja

build-dev:
mkdir -p build
cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug
cd build && make -j
cd build && cmake .. -DCMAKE_BUILD_TYPE=Debug $(CMAKE_EXTRA_ARGS)
cd build && ninja

build-deb:
mkdir -p build
cd build && cmake .. -DCMAKE_BUILD_TYPE=Release -DENABLE_TESTS=OFF $(CMAKE_EXTRA_ARGS)
cd build && ninja

build-make:
mkdir -p build
cd build && cmake .. -DCMAKE_BUILD_TYPE=Release -G Makefile $(CMAKE_EXTRA_ARGS)
cd build && make -j$(JOBS)


man:
mkdir -p build/man/
Expand All @@ -43,12 +61,15 @@ man:
.PHONY: clean
clean:
rm -rf build
rm -rf debian/rtpmidid
rm -rf debian/librtpmidid0
rm -rf debian/librtpmidid0-dev

VALGRINDFLAGS := --leak-check=full --error-exitcode=1
RTPMIDID_ARGS := --port ${PORT} --name devel
RTPMIDID_ARGS := --ini default.ini --port ${PORT} --name devel --control /tmp/rtpmidid.sock

.PHONY: run run-valgrind gdb
run: build
run: build-dev
build/src/rtpmidid $(RTPMIDID_ARGS)

gdb: build-dev
Expand Down Expand Up @@ -107,6 +128,8 @@ install-rtpmidid: build man
cp cli/rtpmidid-cli.py $(PREFIX)/usr/bin/rtpmidid-cli
mkdir -p $(PREFIX)/etc/systemd/system/
cp debian/rtpmidid.service $(PREFIX)/etc/systemd/system/
mkdir -p $(PREFIX)/etc/rtpmidid/
cp default.ini $(PREFIX)/etc/rtpmidid/
mkdir -p $(PREFIX)/usr/share/doc/rtpmidid/
cp README.md $(PREFIX)/usr/share/doc/rtpmidid/
cp LICENSE-daemon.txt $(PREFIX)/usr/share/doc/rtpmidid/LICENSE.txt
Expand Down
141 changes: 103 additions & 38 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ On MacOS there is support included in the OS.

### iPad

To test I used `MIDI Network` and `MIDI Wrench`. The first to manage
To test I used `MIDI Network` and `MIDI Wrench` . The first to manage
connections, the second to test.

I was able to communicate exporting at rtpmidid side connecting my gadget to the
Expand All @@ -59,14 +59,11 @@ support. I will try to list them as I find them:

## How to use `rtpmidid`

recomended use is via debian packages, at https://github.com/davidmoreno/rtpmidid/releases

`rtpmidid` provides two modes of operation, one focused on importing, another on
exporting.
Recomended use is via debian packages, at https://github.com/davidmoreno/rtpmidid/releases

```
Real Time Protocol Music Instrument Digital Interface Daemon - 20.04.5
(C) 2019-2021 David Moreno Montero <[email protected]>
Real Time Protocol Music Instrument Digital Interface Daemon v23.10b1~12~g3495e
(C) 2019-2023 David Moreno Montero <[email protected]>
Share ALSA sequencer MIDI ports using rtpmidi, and viceversa.
rtpmidi allows to use rtpmidi protocol to communicate with MIDI equipement
Expand All @@ -75,53 +72,119 @@ there is a lot more latency. Internet use has not been tested, but may also
deliver high latency.
Options:
--version Show version
--help Show this help
--name <name> Forces a rtpmidi name
--host <address> My default IP. Needed to answer mDNS. Normally guessed but may be attached to another ip.
--port <port> Opens local port as server. Default 5004. Can set several.
--connect <address> Connects the given address. This is default, no need for --connect
--control <path> Creates a control socket. Check CONTROL.md. Default `/var/run/rtpmidid/control.sock`
address for connect:
hostname Connects to hostname:5004 port using rtpmidi
hostname:port Connects to a hostname on a given port
name:hostname:port Connects to a hostname on a given port and forces a name for alsaseq
--ini Loads an INI file as default configuration. Depending on order may overwrite other arguments
--port Opens local port as server. Default 5004.
--name Forces the alsa and rtpmidi name
--alsa-name Forces the alsa name
--rtpmidid-name Forces the rtpmidi name
--control Creates a control socket. Check CONTROL.md. Default `/var/run/rtpmidid/control.sock`
--version Show version
--help Show this help
```

### Importing
By default it only exports all network discovered rtpmidi network ports
into ALSA ports.

For each found mDNS item, and connections to port `5004` (by default), it creates
alsa seq ports which provide the events on those endpoints.
On installation from .deb it uses a default `/etc/rtpmidid/default.ini` ini
file that sets some sensible defaults:

For mDNS discovered endpoints, the connection is delayed until the alsa seq
connection.
- Export as ALSA a "Network" port to which any ALSA connected device is
exported to the network.
- Export as ALSA ports any rtpmidi announced on the network.
- Export a Network rtpmidi port at 5004, to which external devices can connect
to and will be shown as ALSA ports.

Also it can connect to other endpoints by ip and port. It's possible to create
new connection via command line with `rtpmidid-cli connect NAME IP PORT`. There
are variations to connect that skip the name and port.
If there is no ini file, must use `--alsa-name`, `--rtpmidid-name` or `--name`
to create the ALSA Network port, the rtpmidi host port, or both.

### Exporting
Normal rule is just connect with normal ALSA commands and UIs, and the
communication will be transparent.

### rtpmidi `{{hostname}}` port

Announced an rtpmidi service using mDNS (avahi / zeroconf) with the name
of the current host.

Other services can connect to this rtpmidi port and ALSA ports
will be created for this connection.

### ALSA `Network` port.

To export a local alsa sequencer port, connect it to the "Network" port.

It will create the server, announce the mDNS service so other endpoints know it
exist, and accept connections.
It will create the server, announce the mDNS service so other endpoints know
it exist, and accept connections.

MIDI data is rerouted to the proper endpoint by checking the source port.

When connecting the Network port to an input, it merges all the midi events
from all exported services. Normally this is not the desired behaviour, so it is
recomended to export output ports, not input ones. This will be fixed in the
from all exported services. Normally this is not the desired behaviour, so it
is recomended to export output ports, not input ones. This will be fixed in the
future.

### Automatic detection of announced rtpmidi ports

Any port announced on the network will be available at the ALSA port always.

For mDNS discovered endpoints, the connection is delayed until the alsa seq
connection.

### Direct connection

Also it can connect to other endpoints by ip and port. It's possible to create
new connection via command line with `rtpmidid-cli connect NAME IP PORT`. There
are variations to connect that skip the name and port.

### `.ini` files

Ini files can be loaded to set up initial status as described above. This the
default, here as reference:

```ini
# example ini file for rtpmidid
[general]
alsa_name=rtpmidid
control=/var/run/rtpmidid/control.sock

## All announce sections and connect_to can appear several times.

# RTPMIDI announcement requires a firewall rule to allow incoming
# connections on port 5004. If you want to not have an rtpmidi_announce
# section, comment it out or delete it.
# This creates an announced rtpmidi endpoint, and any connection
# will create a new ALSA port.
[rtpmidi_announce]
name={{hostname}}
port=5004

# Alsa announcement requires no firewall as it creates random
# ports for each connection. If you want to not have an alsa_announce
# section, comment it out or delete it.
[alsa_announce]
# Name for the ALSA connection so that when a conneciton is made, an rtpmidi
# is announced.
name=Network Export

# and now some fixed connections
# [connect_to]
# hostname=192.168.1.33
# port=5004
# name=DeepMind12D

# [connect_to]
# hostname=192.168.1.210
# # default port is 5004
# name=midid
```

## Install and Build

There are Debian packages at https://github.com/davidmoreno/rtpmidid/releases .
They are available for Ubuntu 18.04 x64 and Raspbian 32bits, but may work
also on other systems.

To easy build there is a simple makefile, which can be invoked to compile with
`make build`. Use `make` or `make help` to get help on commands.
`make build` . Use `make` or `make help` to get help on commands.

Its possible to create a debian / ubuntu package with `make deb`

Expand All @@ -131,14 +194,14 @@ Requires C++17 (Ubuntu 18.04+), and libfmt-dev, libasound2-dev, libavahi-client-

If you find any bug, please report it to https://github.com/davidmoreno/rtpmidid/issues/

It is very usefull if you can accompany it with the resulting capture file from executing
`make capture`.
It is very usefull if you can accompany it with the resulting capture file from
executing `make capture` .

`make capture` is tuned to capture the network packets at ports `10000` and `10001`, but
can be tuned to other ports with `make capture PORT=5004`.
`make capture` is tuned to capture the network packets at ports `10000` and
`10001`, but can be tuned to other ports with `make capture PORT=5004`.

The port `10000` is the one used for developing. To run a development version of the
rtpmidid server, execute `make run`. There are more options at `make help`.
The port `10000` is the one used for developing. To run a development version of
the rtpmidid server, execute `make run` . There are more options at `make help`.

This captures packets for connections TO rtpmidid, not connecitons FROM rtpmidid.
For those connecitons another port may need to be set.
Expand All @@ -159,11 +222,13 @@ Development status / plan:
- [x] Create the alsa ports for found rtpmidi servers in the network
- [x] When there is any connection to the alsa sequencer port `rtpmidid` creates
the rtpmidi connection

- [x] Any message from alsa seq is sent to the MIDI rtp extreme
- [x] Any message from rtpmidi is replayed on the alsa seq
- [x] Can export local ports, with user deciding which ones to export.
- [x] Server mode at a known port, when remote side request connections, create
the alsa seq virtual port for that connection and connect both ports.

- [x] Allow several connections on the server port. Each its own aseq port.
- [x] Send all MIDI events to rtpmidi
- [x] Receive all MIDI events from rtpmidi
Expand Down
Loading

0 comments on commit 70861b0

Please sign in to comment.